def make_dataset(dataset_name: str, blensor_bin: str, base_dir: str, num_processes=7,
                 seed=42, num_query_points_per_shape=2000):
    """
    Make dataset from meshes.
    :param dataset_name:
    :param blensor_bin:
    :param base_dir:
    :param num_processes: 16 processes need up to 64 GB RAM for the signed distances
    :param seed: only used for the dataset splits
    :param num_query_points_per_shape: should be greater than the training parameter 'patches_per_shape'
    :return:
    """

    dataset_dir = dataset_name

    config_file = os.path.join(base_dir, dataset_dir, 'settings.ini')
    config = configparser.ConfigParser()
    read_config(config, config_file)
    print('Processing dataset: ' + config_file)

    # no signed distances needed, therefore less strict requirements for input meshes
    only_for_evaluation = bool(int(config['general']['only_for_evaluation']))  # default: false
    grid_resolution = int(config['general']['grid_resolution'])  # default: 128  e.g. for marching cubes reconstruction
    epsilon = int(config['general']['epsilon'])  # default: 3
    num_scans_per_mesh_min = int(config['general']['num_scans_per_mesh_min'])  # default: 5
    num_scans_per_mesh_max = int(config['general']['num_scans_per_mesh_max'])  # default: 30
    scanner_noise_sigma_min = float(config['general']['scanner_noise_sigma_min'])  # default: 0.0004, rather a lot: 0.01
    scanner_noise_sigma_max = float(config['general']['scanner_noise_sigma_max'])  # default: 0.0004, rather a lot: 0.01

    patch_radius = point_cloud.get_patch_radius(grid_resolution, epsilon)

    # the user might have removed unwanted input meshes after some processing
    # this moves (intermediate) outputs that don't have inputs anymore to the 'broken' dir
    filter_broken_inputs = True

    dirs_to_clean = \
        ['00_base_meshes',
         '01_base_meshes_ply',
         '02_meshes_cleaned',
         '03_meshes',
         '04_pts', '04_pts_vis', '04_blensor_py',
         '05_patch_dists', '05_patch_ids', '05_query_dist', '05_query_pts',
         '05_patch_ids_grid', '05_query_pts_grid', '05_query_dist_grid',
         '06_poisson_rec', '06_mc_gt_recon', '06_poisson_rec_gt_normals',
         '06_normals', '06_normals/pts', '06_dist_from_p_normals']

    if filter_broken_inputs:
        clean_up_broken_inputs(base_dir=base_dir, dataset_dir=dataset_dir,
                               final_out_dir='00_base_meshes', final_out_extension=None,
                               clean_up_dirs=dirs_to_clean, broken_dir='broken')

    print('### convert base meshes to ply')
    convert_meshes(in_dir_abs=os.path.join(base_dir, dataset_dir, '00_base_meshes'),
                   out_dir_abs=os.path.join(base_dir, dataset_dir, '01_base_meshes_ply'),
                   target_file_type='.ply', num_processes=num_processes)

    if filter_broken_inputs:
        clean_up_broken_inputs(base_dir=base_dir, dataset_dir=dataset_dir,
                               final_out_dir='01_base_meshes_ply', final_out_extension='.ply',
                               clean_up_dirs=dirs_to_clean, broken_dir='broken')

    print('### clean mesh')
    clean_meshes(base_dir=base_dir, dataset_dir=dataset_dir,
                 dir_in_meshes='01_base_meshes_ply', dir_out='02_meshes_cleaned', num_processes=num_processes,
                 num_max_faces=None if only_for_evaluation else 50000,
                 enforce_solid=True)

    if filter_broken_inputs:
        clean_up_broken_inputs(base_dir=base_dir, dataset_dir=dataset_dir,
                               final_out_dir='02_meshes_cleaned', final_out_extension='.ply',
                               clean_up_dirs=dirs_to_clean, broken_dir='broken')

    print('### scale and translate mesh')
    normalize_meshes(base_dir=base_dir, in_dir='02_meshes_cleaned', out_dir='03_meshes', dataset_dir=dataset_dir,
                     num_processes=num_processes)

    print('### sample with Blensor')
    sample_blensor(base_dir=base_dir, dataset_dir=dataset_dir, blensor_bin=blensor_bin,
                   dir_in='03_meshes', dir_out='04_pts', dir_out_vis='04_pts_vis', dir_out_pcd='04_pcd',
                   dir_blensor_scripts='04_blensor_py',
                   num_scans_per_mesh_min=num_scans_per_mesh_min, num_scans_per_mesh_max=num_scans_per_mesh_max,
                   num_processes=num_processes,
                   min_pts_size=0 if only_for_evaluation else 5000,
                   scanner_noise_sigma_min=scanner_noise_sigma_min, scanner_noise_sigma_max=scanner_noise_sigma_max)

    if filter_broken_inputs:
        clean_up_broken_inputs(base_dir=base_dir, dataset_dir=dataset_dir,
                               final_out_dir='04_pts', final_out_extension='.xyz.npy',
                               clean_up_dirs=dirs_to_clean, broken_dir='broken')

    if not only_for_evaluation:
        print('### make query points, calculate signed distances')
        dir_mesh = '03_meshes'
        dir_query_dist = '05_query_dist'
        dir_query_pts_ms = '05_query_pts'
        dir_out_query_vis = '05_query_vis'  # None to disable
        far_query_pts_ratio = 0.5  # 0.1  # not too little or the network fails at the inside classification
        get_query_pts_dist_ms(
            base_dir=base_dir, dataset_dir=dataset_dir, dir_in_mesh=dir_mesh,
            dir_out_query_pts_ms=dir_query_pts_ms,
            dir_out_query_dist_ms=dir_query_dist,
            dir_out_query_vis=dir_out_query_vis,
            patch_radius=patch_radius,
            num_query_pts=num_query_points_per_shape,
            far_query_pts_ratio=far_query_pts_ratio,
            signed_distance_batch_size=500,
            num_processes=num_processes,
            debug=True)

        print('### statistics and clean up')
        if filter_broken_inputs:
            clean_up_broken_inputs(base_dir=base_dir, dataset_dir=dataset_dir,
                                   final_out_dir='05_query_pts' if only_for_evaluation else '05_query_dist',
                                   final_out_extension='.npy',
                                   clean_up_dirs=dirs_to_clean, broken_dir='broken')

    make_dataset_splits(base_dir=base_dir, dataset_dir=dataset_dir,
                        final_out_dir='04_pts' if only_for_evaluation else'05_query_pts',
                        seed=seed, only_test_set=only_for_evaluation, testset_ratio=0.1)

    Make dataset from meshes.
    :param dataset_name:
    :param blensor_bin:
    :param base_dir:
    :param num_processes: 16 processes need up to 64 GB RAM for the signed distances
    :param seed: only used for the dataset splits
    :param num_query_points_per_shape: should be greater than the training parameter 'patches_per_shape'
    :return:
    
make_dataset.py