v2 = p2 - p1 # the cross product is a vector normal to the plane cp = np.cross(v1, v2) a, b, c = cp # This evaluates a * x3 + b * y3 + c * z3 which equals d d = np.dot(cp, p3) print('The equation is {0}x + {1}y + {2}z = {3}'.format(a, b, c, d)) P = Plane(Point3D(start_x, start_y, start_z), Point3D(dir_x, dir_y, dir_z),Point3D(goal_x, goal_y, goal_z)) print(P.equation()) nor_vec = P.normal_vector print(nor_vec) def angle(v1, v2, acute): # v1 is your firsr vector # v2 is your second vector angle = np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))) if (acute == True):
def processBedTower(filename, zProbeOffset, xtarget, ytarget, ztarget, locmarg=0.02): """Reads and analyse a file with four measured bed heights (near towers and in centre). The probe trigger z value (not the actual height) is determined by moving the hot end slowly down and noting the z value where the probe triggers. The distance from the nozzle tip to the probe trigger height is zProbeOffset. The function calculates the number of screw turns required (on M3 screw). This save us a little arithmetic and removes the confusion of which direction to move. . Args: | zProbeOffset (float): the the z value when the probe triggers. friction test in mm. relative to one of the towers, X, Y or Z. B(default: `None`). | locmarg (float): issues a bed titl warning above this threshold Returns: | the axis object for the plot Raises: | No exception is raised. """ print('{}\n{}\n\n'.format(79 * '-', filename)) validlines = [] tdone = False with open(filename, 'r') as fin: lines = fin.readlines() for line in lines: if len(line) > 2: line = line.strip() if '>' in line[0] or '<' in line[0]: line = line[2:] lstl = line.split(' ') # only use lines with Bed X: in them for dataframe if 'Bed X:' in line: # remove unwanted clutter, keep only x,y,z validlines.append([float(lstl[i]) for i in [4, 6, 8]]) # if temperature lines, get values if not tdone and 'ok' in line and 'T:' in line and 'B:' in line: print('Time {} '.format(lstl[0])) print('Bed temperature is {} deg C'.format( lstl[5].split(':')[1])) print('Nozzle temperature is {} deg C'.format( lstl[3].split(':')[1])) tdone = True # make pandas dataframe df = pd.DataFrame(validlines, columns=['x', 'y', 'z']) #name the towers df['Tower'] = df.apply(label_tower, axis=1) df['Target'] = df.apply(target_tower, args=(xtarget, ytarget, ztarget), axis=1) # correct for probe offset to get to metal df['z'] = df['z'] - zProbeOffset # get height at screw df['S'] = df['z'] * 158.6 / (52.85 + np.sqrt(df['x']**2 + df['y']**2)) # now calc offsets to move to target df['dz'] = df['z'] - ztarget df['dz'] = df.apply(delta_tower, args=(xtarget, ytarget, ztarget), axis=1) df['dS'] = df['dz'] * 158.6 / (52.85 + np.sqrt(df['x']**2 + df['y']**2)) # get required turn magnitude df['Trns(deg)'] = 360. * df['dS'] / 0.5 df['Trns/0.25'] = (df['dS'] / 0.5) / 0.25 # from now on work with aggregates dfg = df.groupby(['Tower']) dfr = dfg.aggregate(np.mean) dfr['Std dev'] = dfg.aggregate(np.std)['S'] dfr['Spread'] = dfg.aggregate(np.max)['S'] - dfg.aggregate(np.min)['S'] # centre does not require slant correction dfr['S'].ix['C'] = dfr['z'].ix['C'] # remove value for C outputs dfr.ix['C']['Trns(deg)'] = np.nan dfr.ix['C']['Trns/0.25'] = np.nan dfr.ix['C']['S'] = np.nan dfr.ix['C']['dS'] = np.nan dfr.ix['C']['dz'] = np.nan if 'Xm' in dfr.index: print(dfr.drop(['Xm', 'Ym', 'Zm'], axis=0)) else: print(dfr) print('') # get mean, min and max of the tower averages and tpower and centre twrMean = np.mean((dfr['S']).T[['X', 'Y', 'Z']]) twrMin = np.min((dfr['S']).T[[ 'X', 'Y', 'Z', ]]) twrMax = np.max((dfr['S']).T[['X', 'Y', 'Z']]) twrSpread = twrMax - twrMin bedMean = np.mean((dfr['S']).T[['X', 'Y', 'Z', 'C']]) bedMin = np.min((dfr['S']).T[['X', 'Y', 'Z', 'C']]) bedMax = np.max((dfr['S']).T[['X', 'Y', 'Z', 'C']]) bedSpread = bedMax - bedMin print(' Towers Full bed') print(' (SX,SY,SZ) (SX,SY,SZ,SC)') print('mean {:.3f} {:.3f} '.format(twrMean, bedMean)) print('min {:.3f} {:.3f} '.format(twrMin, bedMin)) print('max {:.3f} {:.3f} '.format(twrMax, bedMax)) print('spread {:.3f} {:.3f} '.format(twrMax - twrMin, bedSpread)) # calculate the plane through the three screws bedplane = Plane(Point3D(dfr.ix['X']['x'], dfr.ix['X']['y'], dfr.ix['X']['z']), Point3D(dfr.ix['Y']['x'], dfr.ix['Y']['y'], dfr.ix['Y']['z']), Point3D(dfr.ix['Z']['x'], dfr.ix['Z']['y'], dfr.ix['Z']['z']), evaluate=False) # process bed normal vector bednormal = Matrix(bedplane.normal_vector).normalized() bnx = float(N(bednormal[0])) bny = float(N(bednormal[1])) bnz = float(N(bednormal[2])) ang = np.arctan2(bny, bnx) norm = np.sqrt(bnx * bnx + bny * bny) print('\nBed normal vector ({:.3e},{:.3e},{:.3e})'.format(bnx, bny, bnz)) print(' projection onto z=0 plane: radius={:.1f} um angle={:.1f} deg'. format(1e6 * norm, 180 * ang / np.pi)) print('\nPrint locus:') print('Plane through SX, SY, and SZ: {}'.format(N(bedplane.equation()))) # measured bed centre bedcentre = Point3D(dfr.ix['C']['x'], dfr.ix['C']['y'], dfr.ix['C']['z']) # displacement between plane at (0,0) and measured z convex = N((N(bedplane.projection(Point3D(0, 0))) - bedcentre).z) # apparent bed direction as seen by printer direc = 'mountain' if convex < 0. else 'valley' slant = 'on a tilted bed' if twrSpread > locmarg else '' print( 'Print locus convexity [plane(0,0) - SC] is {:.3f} mm'.format(convex)) print('The printer perceives the bed as a {} {}'.format(direc, slant)) if twrSpread > locmarg: print( '\n******** WARNING: bed tilt in z {:.3f} mm exceeds {:.3f} mm, {}' .format(twrSpread, locmarg, 'consider levelling'))
from sympy.utilities.lambdify import lambdify from SALib.sample import saltelli random.seed(30) collinear = True section_plane = None x = symbols('x') y = symbols('y') z = symbols('z') max_coord = 10 bounds = [[0,max_coord],[0,max_coord],[0,max_coord]] problem = {'num_vars': 3, 'names': ['x', 'y', 'z'], 'bounds': bounds} while collinear: try: #Selecting three points in the volume pl_pt = random.sample(list(saltelli.sample(problem, 400)), 3) #Plane crossing through them section_plane = Plane(*[Point(pt) for pt in pl_pt]) collinear = False except ValueError: print("Collinear point chosen.") plane_function = lambdify((x,y,z), section_plane.equation(), 'numpy')