Coverage for trimesh/exchange/xyz.py: 89%

36 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-24 04:40 +0000

1import numpy as np 

2 

3from .. import util 

4from ..points import PointCloud 

5 

6 

7def load_xyz(file_obj, delimiter=None, **kwargs): 

8 """ 

9 Load an XYZ file into a PointCloud. 

10 

11 Parameters 

12 ------------ 

13 file_obj : an open file-like object 

14 Source data, ASCII XYZ 

15 delimiter : None or string 

16 Characters used to separate the columns of the file 

17 If not passed will use whitespace or commas 

18 

19 Returns 

20 ---------- 

21 kwargs : dict 

22 Data which can be passed to PointCloud constructor 

23 """ 

24 # read the whole file into memory as a string 

25 raw = util.decode_text(file_obj.read()).strip() 

26 # get the first line to look at 

27 first = raw[: raw.find("\n")].strip() 

28 # guess the column count by looking at the first line 

29 columns = len(first.split()) 

30 if columns < 3: 

31 raise ValueError("not enough columns in xyz file!") 

32 

33 if delimiter is None and "," in first: 

34 # if no delimiter passed and file has commas 

35 delimiter = "," 

36 if delimiter is not None: 

37 # replace delimiter with whitespace so split works 

38 raw = raw.replace(delimiter, " ") 

39 

40 # use string splitting to get array 

41 array = np.array(raw.split(), dtype=np.float64) 

42 # reshape to column count 

43 # if file has different numbers of values 

44 # per row this will fail as it should 

45 data = array.reshape((-1, columns)) 

46 

47 # start with no colors 

48 colors = None 

49 # vertices are the first three columns 

50 vertices = data[:, :3] 

51 if columns == 6: 

52 # RGB colors 

53 colors = np.array(data[:, 3:], dtype=np.uint8) 

54 colors = np.concatenate( 

55 (colors, np.ones((len(data), 1), dtype=np.uint8) * 255), axis=1 

56 ) 

57 elif columns >= 7: 

58 # extract RGBA colors 

59 colors = np.array(data[:, 3:8], dtype=np.uint8) 

60 # add extracted colors and vertices to kwargs 

61 kwargs.update({"vertices": vertices, "colors": colors}) 

62 

63 return kwargs 

64 

65 

66def export_xyz(cloud, write_colors=True, delimiter=None): 

67 """ 

68 Export a PointCloud object to an XYZ format string. 

69 

70 Parameters 

71 ------------- 

72 cloud : trimesh.PointCloud 

73 Geometry in space 

74 write_colors : bool 

75 Write colors or not 

76 delimiter : None or str 

77 What to separate columns with 

78 

79 Returns 

80 -------------- 

81 export : str 

82 Pointcloud in XYZ format 

83 """ 

84 if not isinstance(cloud, PointCloud): 

85 raise ValueError("object must be PointCloud") 

86 

87 # compile data into a blob 

88 data = cloud.vertices 

89 if write_colors and hasattr(cloud, "colors") and cloud.colors is not None: 

90 # stack colors and vertices 

91 data = np.hstack((data, cloud.colors)) 

92 

93 # if delimiter not passed use whitespace 

94 if delimiter is None: 

95 delimiter = " " 

96 # stack blob into XYZ format 

97 export = util.array_to_string(data, col_delim=delimiter) 

98 

99 return export 

100 

101 

102_xyz_loaders = {"xyz": load_xyz} 

103_xyz_exporters = {"xyz": export_xyz}