def main(): set_start_method("spawn") # Imports the part and sets the geometry to an STL file (frameGuide.stl) solidPart = pyslm.Part('inversePyramid') solidPart.setGeometry('../models/inversePyramid.stl') solidPart.origin[0] = 5.0 solidPart.origin[1] = 2.5 solidPart.scaleFactor = 1.0 solidPart.rotation = [0, 0.0, 45] solidPart.dropToPlatform() print(solidPart.boundingBox) # Set the layer thickness layerThickness = 0.04 # [mm] #Perform the hatching operations print('Hatching Started') layers = [] p = Pool(processes=1) d = Manager().dict() d['part'] = solidPart d['layerThickness'] = layerThickness # Rather than give the z position, we give a z index to calculate the z from. numLayers = solidPart.boundingBox[5] / layerThickness z = np.arange(0, numLayers).tolist() # The layer id and manager shared dict are zipped into a list of tuple pairs processList = list(zip([d] * len(z), z)) startTime = time.time() # uncomment to test the time processing in single process #for pc in processList: # calculateLayer(pc) layers = p.map(calculateLayer, processList) print(layers[0]) print('multiprocessing time', time.time() - startTime) p.close() print('Completed Hatching') # Plot the layer geometries using matplotlib # Note: the use of python slices to get the arrays pyslm.visualise.plotLayers(layers[0:-1:10])
""" A simple example showing how to use PySLM with the IslandHatcher approach, which decomposes the layer into several island regions, which are tested for intersection and then the hatches generated are more efficiently clipped. """ import numpy as np import time from shapely.geometry import MultiPolygon import pyslm import pyslm.visualise from pyslm import hatching as hatching # Imports the part and sets the geometry to an STL file (frameGuide.stl) solidPart = pyslm.Part('inversePyramid') solidPart.setGeometry('../models/frameGuide.stl') solidPart.dropToPlatform() solidPart.origin[0] = 5.0 solidPart.origin[1] = 2.5 solidPart.scaleFactor = 2.0 solidPart.rotation = [0, 0.0, np.pi] # Set te slice layer position z = 14.99 # Create a StripeHatcher object for performing any hatching operations myHatcher = hatching.IslandHatcher() myHatcher.islandWidth = 5.0 myHatcher.islandOverlap = -0.1
""" A simple example showing how t use PySLM for generating a Stripe Scan Strategy across a single layer. """ import numpy as np import pyslm import pyslm.analysis.utils as analysis from pyslm import hatching as hatching # Imports the part and sets the geometry to an STL file (frameGuide.stl) solidPart = pyslm.Part('myFrameGuide') solidPart.setGeometry('../models/frameGuide.stl') """ Transform the part: Rotate the part 30 degrees about the Z-Axis - given in degrees Translate by an offset of (5,10) and drop to the platform the z=0 Plate boundary """ solidPart.origin = [5.0, 10.0, 0.0] solidPart.rotation = np.array([0, 0, 30]) solidPart.dropToPlatform() print(solidPart.boundingBox) # Set te slice layer position z = 1.0 # Create a BasicIslandHatcher object for performing any hatching operations ( myHatcher = hatching.BasicIslandHatcher() myHatcher.islandWidth = 3.0 myHatcher.stripeWidth = 5.0
The following example demonstrate the overall structure for creating a multi-layer build file, hatching a 3D model geometry and using a Stripe Hatch Scan Strategy. The file is exported using the Renishaw .mtt translator and then imported to visualise the layer. """ import pyslm import pyslm.analysis import pyslm.visualise from pyslm import hatching as hatching import numpy as np from libSLM.translators import mtt from pyslm import geometry solidPart = pyslm.Part('nut') solidPart.setGeometry('../models/nut.stl') solidPart.origin = [5.0, 10.0, 0.0] solidPart.dropToPlatform() # Create a StripeHatcher object for performing any hatching operations myHatcher = hatching.StripeHatcher() myHatcher.stripeWidth = 5.0 # Set the base hatching parameters which are generated within Hatcher myHatcher.hatchAngle = 10 # [°] myHatcher.volumeOffsetHatch = 0.08 # [mm] myHatcher.spotCompensation = 0.06 # [mm] myHatcher.numInnerContours = 2 myHatcher.numOuterContours = 1
def main(): set_start_method("spawn") # Imports the part and sets the geometry to an STL file (frameGuide.stl) solidPart = pyslm.Part('FrameGuide') solidPart.setGeometry('../models/frameGuide.stl') solidPart.origin[0] = 5.0 solidPart.origin[1] = 2.5 solidPart.scaleFactor = 1.0 solidPart.rotation = rotation solidPart.dropToPlatform() print(solidPart.boundingBox) # Create the multi-threaded map function using the Python multiprocessing library layers = [] p = Pool(processes=8) d = Manager().dict() d['part'] = solidPart d['layerThickness'] = layerThickness # Rather than give the z position, we give a z index to calculate the z from. numLayers = int(solidPart.boundingBox[5] / layerThickness) z = np.arange(0, numLayers).tolist() # The layer id and manager shared dict are zipped into a list of tuple pairs processList = list(zip([d] * len(z), z)) startTime = time.time() print('Beginning Slicing') # uncomment to test the time processing in single process #for pc in processList: # calculateLayer(pc) layers = p.map(calculateLayer, processList) p.close() print('\t Multiprocessing time', time.time() - startTime) print('Slicing Finished') polys = [] for layer in layers: for poly in layer: polys.append(poly) layers = polys """ Calculate total layer statistics: """ totalHeight = solidPart.boundingBox[5] totalVolume = solidPart.volume totalPerimeter = np.sum([layer.length for layer in layers]) * numCountourOffsets totalArea = np.sum([layer.area for layer in layers]) print('\nStatistics:') print('\tDiscretised volume {:.2f} cm3'.format(totalArea * layerThickness / 1e3)) print("\tNum Layers {:d} Height: {:.2f}".format(numLayers, totalHeight)) print( "\tVolume: {:.2f} cm3, Area: {:.2f} mm2, Contour Perimeter: {:.2f} mm". format(totalVolume / 1000, totalArea, totalPerimeter)) """ Calculate the time estimates: This calculates the total scan time using the layer slice approach """ hatchTimeEstimate = totalArea / hatchDistance / hatchLaserScanSpeed boundaryTimeEstimate = totalPerimeter / contourLaserScanSpeed scanTime = hatchTimeEstimate + boundaryTimeEstimate recoaterTimeEstimate = numLayers * layerRecoatTime totalTime = hatchTimeEstimate + boundaryTimeEstimate + recoaterTimeEstimate print('\nLayer Approach:') print( "\tScan Time: {:.2f} hr, Recoat Time: {:.2f} hr, Total time: {:.3f} hr" .format(scanTime / 3600, recoaterTimeEstimate / 3600, totalTime / 3600)) """ Calculate using a simplified approach Projected Area: Calculates the projected vertical area of the part """ print('\nApproximate Build Time Estimate:') # Calculate the vertical face angles v0 = np.array([[0., 0., 1.0]]) v1 = solidPart.geometry.face_normals sin_theta = np.sqrt((1 - np.dot(v0, v1.T)**2)) triAreas = solidPart.geometry.area_faces * sin_theta projectedArea = np.sum(triAreas) print('\tProjected surface area: {:.3f}'.format(projectedArea)) print('\tSurface area: {:.3f}'.format(solidPart.surfaceArea)) approxScanTime = solidPart.volume / ( hatchDistance * hatchLaserScanSpeed * layerThickness ) + solidPart.surfaceArea / (contourLaserScanSpeed * layerThickness) approxProjectedScanTime = solidPart.volume / ( hatchDistance * hatchLaserScanSpeed * layerThickness ) + projectedArea / (contourLaserScanSpeed * layerThickness) print('\tApprox scan time *surface) {:.2f} hr'.format(approxScanTime / 3600)) print('\tApprox scan time (using projected area): {:.2f} hr'.format( approxProjectedScanTime / 3600))