kopia lustrzana https://github.com/vilemduha/blendercam
				
				
				
			
		
			
				
	
	
		
			174 wiersze
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			174 wiersze
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
	
| """Fabex 'oclSample.py'
 | |
| 
 | |
| Functions to sample mesh or curve data for OpenCAMLib processing.
 | |
| """
 | |
| 
 | |
| from math import radians, tan
 | |
| 
 | |
| try:
 | |
|     import ocl
 | |
| except ImportError:
 | |
|     try:
 | |
|         import opencamlib as ocl
 | |
|     except ImportError:
 | |
|         pass
 | |
| 
 | |
| try:
 | |
|     from bl_ext.blender_org.stl_format_legacy import blender_utils
 | |
| except ImportError:
 | |
|     pass
 | |
| 
 | |
| import mathutils
 | |
| 
 | |
| from ..constants import OCL_SCALE, _PREVIOUS_OCL_MESH
 | |
| from ..simple import activate
 | |
| from ..exception import CamException
 | |
| from ..operators.async_op import progress_async
 | |
| 
 | |
| 
 | |
| def get_oclSTL(operation):
 | |
|     """Get the oclSTL representation from the provided operation.
 | |
| 
 | |
|     This function iterates through the objects in the given operation and
 | |
|     constructs an oclSTL object by extracting triangle data from mesh,
 | |
|     curve, font, or surface objects. It activates each object and checks its
 | |
|     type to determine if it can be processed. If no valid objects are found,
 | |
|     it raises an exception.
 | |
| 
 | |
|     Args:
 | |
|         operation (Operation): An object containing a collection of objects
 | |
| 
 | |
|     Returns:
 | |
|         ocl.STLSurf: An oclSTL object containing the triangles derived from
 | |
|         the valid objects.
 | |
| 
 | |
|     Raises:
 | |
|         CamException: If no mesh, curve, or equivalent object is found in
 | |
|     """
 | |
|     me = None
 | |
|     oclSTL = ocl.STLSurf()
 | |
|     found_mesh = False
 | |
|     for collision_object in operation.objects:
 | |
|         activate(collision_object)
 | |
|         if (
 | |
|             collision_object.type == "MESH"
 | |
|             or collision_object.type == "CURVE"
 | |
|             or collision_object.type == "FONT"
 | |
|             or collision_object.type == "SURFACE"
 | |
|         ):
 | |
|             found_mesh = True
 | |
|             global_matrix = mathutils.Matrix.Identity(4)
 | |
|             faces = blender_utils.faces_from_mesh(
 | |
|                 collision_object, global_matrix, operation.use_modifiers
 | |
|             )
 | |
|             for face in faces:
 | |
|                 t = ocl.Triangle(
 | |
|                     ocl.Point(
 | |
|                         face[0][0] * OCL_SCALE,
 | |
|                         face[0][1] * OCL_SCALE,
 | |
|                         (face[0][2] + operation.skin) * OCL_SCALE,
 | |
|                     ),
 | |
|                     ocl.Point(
 | |
|                         face[1][0] * OCL_SCALE,
 | |
|                         face[1][1] * OCL_SCALE,
 | |
|                         (face[1][2] + operation.skin) * OCL_SCALE,
 | |
|                     ),
 | |
|                     ocl.Point(
 | |
|                         face[2][0] * OCL_SCALE,
 | |
|                         face[2][1] * OCL_SCALE,
 | |
|                         (face[2][2] + operation.skin) * OCL_SCALE,
 | |
|                     ),
 | |
|                 )
 | |
|                 oclSTL.addTriangle(t)
 | |
|         # FIXME needs to work with collections
 | |
|     if not found_mesh:
 | |
|         raise CamException(
 | |
|             "This Operation Requires a Mesh or Curve Object or Equivalent (e.g. Text, Volume)."
 | |
|         )
 | |
|     return oclSTL
 | |
| 
 | |
| 
 | |
| async def ocl_sample(operation, chunks, use_cached_mesh=False):
 | |
|     """Sample points using a specified cutter and operation.
 | |
| 
 | |
|     This function takes an operation and a list of chunks, and samples
 | |
|     points based on the specified cutter type and its parameters. It
 | |
|     supports various cutter types such as 'END', 'BALLNOSE', 'VCARVE',
 | |
|     'CYLCONE', 'BALLCONE', and 'BULLNOSE'. The function can also utilize a
 | |
|     cached mesh for efficiency. The sampled points are returned after
 | |
|     processing all chunks.
 | |
| 
 | |
|     Args:
 | |
|         operation (Operation): An object containing the cutter type, diameter,
 | |
|             minimum Z value, tip angle, and other relevant parameters.
 | |
|         chunks (list): A list of chunk objects that contain point data to be
 | |
|             processed.
 | |
|         use_cached_mesh (bool): A flag indicating whether to use a cached mesh
 | |
|             if available. Defaults to False.
 | |
| 
 | |
|     Returns:
 | |
|         list: A list of sampled CL points generated by the cutter.
 | |
|     """
 | |
| 
 | |
|     global _PREVIOUS_OCL_MESH
 | |
| 
 | |
|     op_cutter_type = operation.cutter_type
 | |
|     op_cutter_diameter = operation.cutter_diameter
 | |
|     op_minz = operation.min_z
 | |
|     op_cutter_tip_angle = radians(operation.cutter_tip_angle) / 2
 | |
|     if op_cutter_type == "VCARVE":
 | |
|         cutter_length = (op_cutter_diameter / tan(op_cutter_tip_angle)) / 2
 | |
|     else:
 | |
|         cutter_length = 10
 | |
| 
 | |
|     cutter = None
 | |
| 
 | |
|     if op_cutter_type == "END":
 | |
|         cutter = ocl.CylCutter((op_cutter_diameter + operation.skin * 2) * 1000, cutter_length)
 | |
|     elif op_cutter_type == "BALLNOSE":
 | |
|         cutter = ocl.BallCutter((op_cutter_diameter + operation.skin * 2) * 1000, cutter_length)
 | |
|     elif op_cutter_type == "VCARVE":
 | |
|         cutter = ocl.ConeCutter(
 | |
|             (op_cutter_diameter + operation.skin * 2) * 1000, op_cutter_tip_angle, cutter_length
 | |
|         )
 | |
|     elif op_cutter_type == "CYLCONE":
 | |
|         cutter = ocl.CylConeCutter(
 | |
|             (operation.cylcone_diameter / 2 + operation.skin) * 2000,
 | |
|             (op_cutter_diameter + operation.skin * 2) * 1000,
 | |
|             op_cutter_tip_angle,
 | |
|         )
 | |
|     elif op_cutter_type == "BALLCONE":
 | |
|         cutter = ocl.BallConeCutter(
 | |
|             (operation.ball_radius + operation.skin) * 2000,
 | |
|             (op_cutter_diameter + operation.skin * 2) * 1000,
 | |
|             op_cutter_tip_angle,
 | |
|         )
 | |
|     elif op_cutter_type == "BULLNOSE":
 | |
|         cutter = ocl.BullCutter(
 | |
|             (op_cutter_diameter + operation.skin * 2) * 1000,
 | |
|             operation.bull_corner_radius * 1000,
 | |
|             cutter_length,
 | |
|         )
 | |
|     else:
 | |
|         print("Cutter Unsupported: {0}\n".format(op_cutter_type))
 | |
|         quit()
 | |
| 
 | |
|     bdc = ocl.BatchDropCutter()
 | |
|     if use_cached_mesh and _PREVIOUS_OCL_MESH is not None:
 | |
|         oclSTL = _PREVIOUS_OCL_MESH
 | |
|     else:
 | |
|         oclSTL = get_oclSTL(operation)
 | |
|         _PREVIOUS_OCL_MESH = oclSTL
 | |
|     bdc.setSTL(oclSTL)
 | |
|     bdc.setCutter(cutter)
 | |
| 
 | |
|     for chunk in chunks:
 | |
|         for coord in chunk.get_points_np():
 | |
|             bdc.appendPoint(ocl.CLPoint(coord[0] * 1000, coord[1] * 1000, op_minz * 1000))
 | |
|     await progress_async("OpenCAMLib Sampling")
 | |
|     bdc.run()
 | |
| 
 | |
|     cl_points = bdc.getCLPoints()
 | |
| 
 | |
|     return cl_points
 |