def run(starter): """This function goes through the complete Pychop3D process, including the beam search for the optimal cutting planes, determining the connector locations, adding the connectors to the part meshes, then saving the STLs, the tree json and the configuration file. :param starter: Either an unpartitioned mesh or an already partitioned tree to begin the process using :type starter: `trimesh.Trimesh` :type starter: `bsp_tree.BSPTree` """ config = Configuration.config # basic logging setup logging.basicConfig( level=logging.INFO, format="%(asctime)s %(name)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler(os.path.join(config.directory, "info.log")), logging.StreamHandler() ]) # mark starting time t0 = time.time() # complete the beam search using the starter, no search will take place if the starter tree is already # adequately partitioned tree = beam_search(starter) logger.info(f"Best BSP-tree found in {time.time() - t0} seconds") # save the tree now in case the connector placement fails utils.save_tree(tree, "final_tree.json") # mark starting time t0 = time.time() logger.info("finding best connector arrangement") # create connector placer object, this creates all potential connectors and determines their collisions connector_placer = connector.ConnectorPlacer(tree) if connector_placer.n_connectors > 0: # use simulated annealing to determine the best combination of connectors state = connector_placer.simulated_annealing_connector_placement() logger.info( f"Best connector arrangement found in {time.time() - t0} seconds") # save the final tree including the state utils.save_tree(tree, "final_tree_with_connectors.json", state) # add the connectors / subtract the slots from the parts of the partitioned input object logger.info(f"inserting {state.sum()} connectors...") tree = connector_placer.insert_connectors(tree, state) # export the parts of the partitioned object utils.export_tree_stls(tree) logger.info("Finished")
def test_sa_objective_2(): """Verifies: - large faces prefer multiple connectors """ config = Configuration.config config.connector_spacing = 5 mesh = trimesh.primitives.Box(extents=[30, 30, 80]) tree = bsp_tree.BSPTree(mesh) normal = np.array([0, 0, 1]) origin = np.zeros(3) tree = bsp_tree.expand_node(tree, tree.nodes[0].path, (origin, normal)) connector_placer = connector.ConnectorPlacer(tree) # single connector state = np.zeros(connector_placer.n_connectors, dtype=bool) state[12] = True ob1 = connector_placer.evaluate_connector_objective(state) # double connector in opposite corners state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[24] = True ob2 = connector_placer.evaluate_connector_objective(state) # connector in each corner state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[4] = True state[20] = True state[24] = True ob3 = connector_placer.evaluate_connector_objective(state) # connector in each corner and in middle (too many connectors) state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[4] = True state[12] = True state[20] = True state[24] = True ob4 = connector_placer.evaluate_connector_objective(state) assert ob1 > ob2 > ob3 assert ob4 > ob3 config.restore_defaults()
def test_sa_objective_2(config): """Verifies: - large faces prefer multiple connectors NOTE: every time grid_sample code changes, this will need to be changed which obviously isnt ideal """ config.connector_spacing = 5 mesh = trimesh.primitives.Box(extents=[30, 30, 80]) tree = bsp_tree.BSPTree(mesh) normal = np.array([0, 0, 1]) origin = np.zeros(3) tree, result = bsp_tree.expand_node(tree, tree.nodes[0].path, (origin, normal)) connector_placer = connector.ConnectorPlacer(tree) # single connector state = np.zeros(connector_placer.n_connectors, dtype=bool) state[12] = True ob1 = connector_placer.evaluate_connector_objective(state) # double connector in opposite corners state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[24] = True ob2 = connector_placer.evaluate_connector_objective(state) # connector in each corner state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[4] = True state[20] = True state[24] = True ob3 = connector_placer.evaluate_connector_objective(state) # connector in each corner and in middle (too many connectors) state = np.zeros(connector_placer.n_connectors, dtype=bool) state[0] = True state[4] = True state[12] = True state[20] = True state[24] = True ob4 = connector_placer.evaluate_connector_objective(state) assert ob1 > ob2 > ob3 assert ob4 > ob3
def test_sa_objective_1(): """Verifies: - connected components without a connector are penalized - small connected components with a single connector have a reasonably low objective - connected components with a connector collision are penalized """ config = Configuration.config mesh = trimesh.primitives.Box(extents=[10, 10, 40]) tree = bsp_tree.BSPTree(mesh) normal = np.array([0, 0, 1]) origin = np.zeros(3) tree = bsp_tree.expand_node(tree, tree.nodes[0].path, (origin, normal)) connector_placer = connector.ConnectorPlacer(tree) assert connector_placer.evaluate_connector_objective(np.array([False, False])) >= 1 / config.empty_cc_penalty ob2 = connector_placer.evaluate_connector_objective(np.array([False, True])) ob3 = connector_placer.evaluate_connector_objective(np.array([True, False])) assert ob2 == ob3 assert ob2 < 5 assert connector_placer.evaluate_connector_objective(np.array([True, True])) >= config.connector_collision_penalty
def main(mesh_filepath): # set configuration options config = Configuration.config config.name = 'output' config.mesh = mesh_filepath config.beam_width = 3 config.connector_diameter = 6 config.connector_spacing = 10 config.part_separation = True config.scale_factor = 5 config.save() # open the input mesh as the starter starter = utils.open_mesh() # separate pieces if config.part_separation and starter.body_count > 1: starter = utils.separate_starter(starter) # complete the beam search using the starter, no search will take place if the starter tree is adequately partitioned tree = beam_search(starter) # save the tree now in case the connector placement fails utils.save_tree(tree, "final_tree.json") try: # mark starting time t0 = time.time() # create connector placer object, this creates all potential connectors and determines their collisions connector_placer = connector.ConnectorPlacer(tree) if connector_placer.n_connectors > 0: # use simulated annealing to determine the best combination of connectors state = connector_placer.simulated_annealing_connector_placement() # save the final tree including the state utils.save_tree(tree, "final_tree_with_connectors.json", state) # add the connectors / subtract the slots from the parts of the partitioned input object tree = connector_placer.insert_connectors(tree, state) except Exception as e: # fail gently so that the STLs still get exported warnings.warn(e, Warning, stacklevel=2) # export the parts of the partitioned object utils.export_tree_stls(tree)
def run(starter): """This function goes through the complete Pychop3D process, including the beam search for the optimal cutting planes, determining the connector locations, adding the connectors to the part meshes, then saving the STLs, the tree json and the configuration file. :param starter: Either an unpartitioned mesh or an already partitioned tree to begin the process using :type starter: `trimesh.Trimesh` :type starter: `bsp_tree.BSPTree` """ # mark starting time t0 = time.time() # complete the beam search using the starter, no search will take place if the starter tree is already # adequately partitioned tree = beam_search(starter) logger.info(f"Best BSP-tree found in {time.time() - t0} seconds") # save the tree now in case the connector placement fails utils.save_tree(tree, "final_tree.json") try: # mark starting time t0 = time.time() # create connector placer object, this creates all potential connectors and determines their collisions connector_placer = connector.ConnectorPlacer(tree) if connector_placer.n_connectors > 0: # use simulated annealing to determine the best combination of connectors state = connector_placer.simulated_annealing_connector_placement() # save the final tree including the state utils.save_tree(tree, "final_tree_with_connectors.json", state) # add the connectors / subtract the slots from the parts of the partitioned input object tree = connector_placer.insert_connectors(tree, state) logger.info( f"Best connector arrangement found in {time.time() - t0} seconds") except Exception as e: # fail gently so that the STLs still get exported logger.error("Connector placement failed") logger.error(e) # export the parts of the partitioned object utils.export_tree_stls(tree) logger.info("Finished")
import time import logging from pychop3d import utils from pychop3d import connector from pychop3d.configuration import Configuration logging.basicConfig( level=logging.INFO, format="%(asctime)s %(name)s [%(levelname)s] %(message)s", handlers=[logging.StreamHandler()]) Configuration.config = Configuration( "C:\\Users\\Greg\\Documents\\things\\table\\config.yml") tree_file = "C:\\Users\\Greg\\Documents\\things\\table\\table_platform_20200503_040048\\final_tree_with_connectors.json" tree = utils.open_tree(tree_file) connector_placer = connector.ConnectorPlacer(tree) state = utils.load_connector_configuration(tree_file) tree = connector_placer.insert_connectors(tree, state) utils.export_tree_stls(tree)