/scripts/process_data/convex_hull.py

https://github.com/ranahanocka/point2mesh · Python · 99 lines · 75 code · 24 blank · 0 comment · 17 complexity · bbb744ed718fcfecde88fe15ceec9119 MD5 · raw file

  1. import trimesh
  2. from models.layers.mesh import *
  3. import argparse
  4. import pathlib
  5. from utils import *
  6. import warnings
  7. def run(args):
  8. xyz, _ = read_pts(args.i)
  9. m = trimesh.convex.convex_hull(xyz[:, :3])
  10. vs, faces = m.vertices, m.faces
  11. export(args.o, vs, faces)
  12. if args.blender:
  13. blender_rehull(args.o, args.o, args.blender_res, args.blender_path)
  14. else:
  15. inplace_manifold(args.o, args.manifold_res, args.manifold_path)
  16. num_faces = count_faces(args.o)
  17. if args.blender:
  18. num_faces /= 2
  19. num_faces = int(num_faces)
  20. if num_faces < args.faces:
  21. software = 'blender' if args.blender else 'manifold'
  22. warnings.warn(f'only {num_faces} faces where generated by {software}. '
  23. f'try increasing --{software}-res to achieve the desired target of {args.faces} faces')
  24. else:
  25. inplace_simplify(args.o, args.faces, args.manifold_path)
  26. print('*** Done! ****')
  27. def check_args(args):
  28. if not args.i.exists():
  29. raise FileNotFoundError('can\' find input file')
  30. if args.blender:
  31. if not (args.blender_path / 'blender').exists():
  32. raise FileNotFoundError('can\' find blender')
  33. else:
  34. if not (args.manifold_path / 'manifold').exists():
  35. raise FileNotFoundError('can\' find manifold software')
  36. if not (args.manifold_path / 'simplify').exists():
  37. raise FileNotFoundError('can\' find simplify software')
  38. if not args.o:
  39. args.o = args.i.with_name('.'.join(args.i.name.split('.')[:-1]) + '_hull.obj')
  40. else:
  41. args.o = Path(args.o)
  42. def count_faces(path: Path) -> int:
  43. with open(path, 'r') as file:
  44. lines = file.read().split('\n')
  45. return sum(map(lambda x: x.startswith('f'), lines))
  46. def inplace_manifold(path: Path, res: int, manifold_software_path: Path):
  47. cmd = f'{manifold_software_path}/manifold {path} {path} {res}'
  48. os.system(cmd)
  49. def inplace_simplify(path: Path, faces: int, manifold_software_path: Path):
  50. cmd = f'{manifold_software_path}/simplify -i {path} -o {path} -f {faces}'
  51. os.system(cmd)
  52. def blender_rehull(target: Path, dest: Path, res: int, blender_path: Path):
  53. base_path = pathlib.Path(__file__).parent.absolute()
  54. cmd = f'{blender_path}/blender --background --python {base_path}/blender_scripts/blender_hull.py' \
  55. f' {target} {res} {dest} > /dev/null 2>&1'
  56. os.system(cmd)
  57. if __name__ == '__main__':
  58. base_path = os.path.dirname(os.path.abspath(__file__))
  59. parser = argparse.ArgumentParser(description='Convex hull maker')
  60. parser.add_argument('--i', type=Path, required=True,
  61. help='path to read .xyz/.npts or .ply from')
  62. parser.add_argument('--faces', type=int, required=True, help='#target of faces for the convex hull')
  63. parser.add_argument('--o', type=str, required=False,
  64. help='path to output convex hull obj to', default='')
  65. parser.add_argument('--manifold-path', type=Path, required=False,
  66. help='path to build folder containing manifold and simplify software')
  67. parser.add_argument('--manifold-res', type=int, default=5000, required=False,
  68. help='resolution for Manifold software')
  69. parser.add_argument('--blender', action='store_true')
  70. parser.add_argument('--blender-res', type=int, default=5, required=False,
  71. help='resolution for making convex hulls with blender software')
  72. parser.add_argument('--blender-path', type=Path, required=False, help='path to folder containing blender')
  73. args = parser.parse_args()
  74. check_args(args)
  75. run(args)