subsurface-terra 2025.1.0rc15__py3-none-any.whl → 2025.1.0rc17__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. subsurface/__init__.py +31 -31
  2. subsurface/_version.py +34 -21
  3. subsurface/api/__init__.py +13 -13
  4. subsurface/api/interfaces/__init__.py +3 -3
  5. subsurface/api/interfaces/stream.py +136 -136
  6. subsurface/api/reader/read_wells.py +78 -78
  7. subsurface/core/geological_formats/boreholes/_combine_trajectories.py +117 -117
  8. subsurface/core/geological_formats/boreholes/_map_attrs_to_survey.py +236 -234
  9. subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +163 -163
  10. subsurface/core/geological_formats/boreholes/boreholes.py +140 -140
  11. subsurface/core/geological_formats/boreholes/collars.py +26 -26
  12. subsurface/core/geological_formats/boreholes/survey.py +86 -86
  13. subsurface/core/geological_formats/fault.py +47 -47
  14. subsurface/core/reader_helpers/reader_unstruct.py +11 -11
  15. subsurface/core/reader_helpers/readers_data.py +130 -130
  16. subsurface/core/reader_helpers/readers_wells.py +13 -13
  17. subsurface/core/structs/__init__.py +3 -3
  18. subsurface/core/structs/base_structures/__init__.py +2 -2
  19. subsurface/core/structs/base_structures/_aux.py +69 -0
  20. subsurface/core/structs/base_structures/_liquid_earth_mesh.py +121 -121
  21. subsurface/core/structs/base_structures/_unstructured_data_constructor.py +70 -70
  22. subsurface/core/structs/base_structures/base_structures_enum.py +6 -6
  23. subsurface/core/structs/base_structures/structured_data.py +282 -282
  24. subsurface/core/structs/base_structures/unstructured_data.py +338 -319
  25. subsurface/core/structs/structured_elements/octree_mesh.py +10 -10
  26. subsurface/core/structs/structured_elements/structured_grid.py +59 -59
  27. subsurface/core/structs/structured_elements/structured_mesh.py +9 -9
  28. subsurface/core/structs/unstructured_elements/__init__.py +3 -3
  29. subsurface/core/structs/unstructured_elements/line_set.py +72 -72
  30. subsurface/core/structs/unstructured_elements/point_set.py +43 -43
  31. subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +35 -35
  32. subsurface/core/structs/unstructured_elements/triangular_surface.py +62 -62
  33. subsurface/core/utils/utils_core.py +38 -38
  34. subsurface/modules/reader/__init__.py +13 -13
  35. subsurface/modules/reader/faults/faults.py +80 -80
  36. subsurface/modules/reader/from_binary.py +46 -46
  37. subsurface/modules/reader/mesh/_GOCAD_mesh.py +82 -82
  38. subsurface/modules/reader/mesh/_trimesh_reader.py +447 -447
  39. subsurface/modules/reader/mesh/csv_mesh_reader.py +53 -53
  40. subsurface/modules/reader/mesh/dxf_reader.py +177 -177
  41. subsurface/modules/reader/mesh/glb_reader.py +30 -30
  42. subsurface/modules/reader/mesh/mx_reader.py +232 -232
  43. subsurface/modules/reader/mesh/obj_reader.py +53 -53
  44. subsurface/modules/reader/mesh/omf_mesh_reader.py +43 -43
  45. subsurface/modules/reader/mesh/surface_reader.py +56 -56
  46. subsurface/modules/reader/mesh/surfaces_api.py +41 -41
  47. subsurface/modules/reader/profiles/__init__.py +3 -3
  48. subsurface/modules/reader/profiles/profiles_core.py +197 -197
  49. subsurface/modules/reader/read_netcdf.py +38 -38
  50. subsurface/modules/reader/topography/__init__.py +7 -7
  51. subsurface/modules/reader/topography/topo_core.py +100 -100
  52. subsurface/modules/reader/volume/read_grav3d.py +447 -428
  53. subsurface/modules/reader/volume/read_volume.py +327 -230
  54. subsurface/modules/reader/volume/segy_reader.py +105 -105
  55. subsurface/modules/reader/volume/seismic.py +173 -173
  56. subsurface/modules/reader/volume/volume_utils.py +43 -43
  57. subsurface/modules/reader/wells/DEP/__init__.py +43 -43
  58. subsurface/modules/reader/wells/DEP/_well_files_reader.py +167 -167
  59. subsurface/modules/reader/wells/DEP/_wells_api.py +61 -61
  60. subsurface/modules/reader/wells/DEP/_welly_reader.py +180 -180
  61. subsurface/modules/reader/wells/DEP/pandas_to_welly.py +212 -212
  62. subsurface/modules/reader/wells/_read_to_df.py +57 -57
  63. subsurface/modules/reader/wells/read_borehole_interface.py +148 -148
  64. subsurface/modules/reader/wells/wells_utils.py +68 -68
  65. subsurface/modules/tools/mocking_aux.py +104 -104
  66. subsurface/modules/visualization/__init__.py +2 -2
  67. subsurface/modules/visualization/to_pyvista.py +320 -320
  68. subsurface/modules/writer/to_binary.py +12 -12
  69. subsurface/modules/writer/to_rex/common.py +78 -78
  70. subsurface/modules/writer/to_rex/data_struct.py +74 -74
  71. subsurface/modules/writer/to_rex/gempy_to_rexfile.py +791 -791
  72. subsurface/modules/writer/to_rex/material_encoder.py +44 -44
  73. subsurface/modules/writer/to_rex/mesh_encoder.py +152 -152
  74. subsurface/modules/writer/to_rex/to_rex.py +115 -115
  75. subsurface/modules/writer/to_rex/utils.py +15 -15
  76. subsurface/optional_requirements.py +116 -116
  77. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/METADATA +194 -194
  78. subsurface_terra-2025.1.0rc17.dist-info/RECORD +99 -0
  79. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/WHEEL +1 -1
  80. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/licenses/LICENSE +203 -203
  81. subsurface_terra-2025.1.0rc15.dist-info/RECORD +0 -98
  82. {subsurface_terra-2025.1.0rc15.dist-info → subsurface_terra-2025.1.0rc17.dist-info}/top_level.txt +0 -0
@@ -1,232 +1,232 @@
1
- import re
2
- import warnings
3
- from typing import Optional, TextIO
4
- import numpy as np
5
- from subsurface.core.structs import UnstructuredData
6
- from ._GOCAD_mesh import GOCADMesh
7
-
8
-
9
- def mx_to_unstruc_from_binary(stream: TextIO) -> UnstructuredData:
10
- content = stream.read()
11
- goCADMeshes = _parse_lines(content)
12
- unstruct_data = _meshes_to_unstruct(goCADMeshes)
13
- return unstruct_data
14
-
15
-
16
- def mx_to_unstruct_from_file(filename: str) -> UnstructuredData:
17
- # Split the file into meshes
18
- with open(filename, 'r') as f:
19
- content: str = f.read()
20
- goCAD_meshes = _parse_lines(content)
21
- unstruct_data = _meshes_to_unstruct(goCAD_meshes)
22
-
23
- return unstruct_data
24
-
25
-
26
- def _parse_lines(content: str) -> list[GOCADMesh]:
27
- meshes = []
28
- mesh_blocks = re.split(r'(?=GOCAD TSurf 1)', content)
29
- # Remove any empty strings from the list
30
-
31
- mesh_blocks = [block for block in mesh_blocks if block.strip()]
32
- # Use multiprocessing Pool to parse meshes in parallel
33
- # with Pool(processes=cpu_count()) as pool:
34
- # meshes = pool.map(process_mesh, mesh_blocks)
35
- for mesh_block in mesh_blocks:
36
- mesh_lines = mesh_block.split('\n')
37
- mesh = _process_mesh(mesh_lines)
38
- if mesh:
39
- meshes.append(mesh)
40
- return meshes
41
-
42
-
43
- def _meshes_to_unstruct(meshes: list[GOCADMesh]) -> UnstructuredData:
44
- # ? I added this function to the Solutions class
45
- n_meshes = len(meshes)
46
-
47
- vertex_array = np.concatenate([meshes[i].vertices for i in range(n_meshes)])
48
- simplex_array = np.concatenate([meshes[i].vectorized_edges for i in range(n_meshes)])
49
- unc, count = np.unique(simplex_array, axis=0, return_counts=True)
50
-
51
- # * Prepare the simplex array
52
- simplex_array = meshes[0].vectorized_edges
53
- adder = 0
54
- for i in range(1, n_meshes):
55
- adder += np.max(meshes[i - 1].vectorized_edges) + 1
56
- add_mesh = meshes[i].vectorized_edges + adder
57
- simplex_array = np.append(simplex_array, add_mesh, axis=0)
58
-
59
- # * Prepare the cells_attr array
60
- ids_array = np.ones(simplex_array.shape[0])
61
- l0 = 0
62
- id = 1
63
- for mesh in meshes:
64
- l1 = l0 + mesh.vectorized_edges.shape[0]
65
- ids_array[l0:l1] = id
66
- l0 = l1
67
- id += 1
68
-
69
- # * Create the unstructured data
70
- import pandas as pd
71
- unstructured_data = UnstructuredData.from_array(
72
- vertex=vertex_array,
73
- cells=simplex_array,
74
- cells_attr=pd.DataFrame(ids_array, columns=['id']) # TODO: We have to create an array with the shape of simplex array with the id of each simplex
75
- )
76
-
77
- return unstructured_data
78
-
79
-
80
- def _process_mesh(mesh_lines) -> Optional[GOCADMesh]:
81
- mesh = GOCADMesh()
82
- in_header = False
83
- in_coord_sys = False
84
- in_property_class_header = False
85
- in_tface = False
86
- current_property_class_header = {}
87
- vertex_list = []
88
- vertex_indices = []
89
- triangle_list = []
90
- vid_to_index = {} # Map from vertex id to index in vertex_list
91
-
92
- for line in mesh_lines:
93
- line = line.strip()
94
-
95
- if line.startswith('HEADER {'):
96
- in_header = True
97
- continue
98
-
99
- if in_header:
100
- if line == '}':
101
- in_header = False
102
- else:
103
- key_value = line.split(':', 1)
104
- if len(key_value) == 2:
105
- key, value = key_value
106
- mesh.header[key.strip()] = value.strip()
107
- else:
108
- parts = line.split()
109
- if len(parts) == 2:
110
- key, value = parts
111
- mesh.header[key.strip()] = value.strip()
112
- else:
113
- mesh.header[line.strip()] = None
114
- continue
115
-
116
- if line.startswith('GOCAD_ORIGINAL_COORDINATE_SYSTEM'):
117
- in_coord_sys = True
118
- continue
119
- if in_coord_sys:
120
- if line == 'END_ORIGINAL_COORDINATE_SYSTEM':
121
- in_coord_sys = False
122
- else:
123
- key_value = line.split(' ', 1)
124
- if len(key_value) == 2:
125
- key, value = key_value
126
- mesh.coordinate_system[key.strip()] = value.strip()
127
- else:
128
- mesh.coordinate_system[line.strip()] = None
129
- continue
130
-
131
- if line.startswith('PROPERTY_CLASS_HEADER'):
132
- in_property_class_header = True
133
- current_property_class_header = {'name': line[len('PROPERTY_CLASS_HEADER'):].strip()}
134
- continue
135
-
136
- if in_property_class_header:
137
- if line == '}':
138
- in_property_class_header = False
139
- mesh.property_class_headers.append(current_property_class_header)
140
- current_property_class_header = {}
141
- else:
142
- key_value = line.split(':', 1)
143
- if len(key_value) == 2:
144
- key, value = key_value
145
- current_property_class_header[key.strip()] = value.strip()
146
- else:
147
- key_value = line.split(' ', 1)
148
- if len(key_value) == 2:
149
- key, value = key_value
150
- current_property_class_header[key.strip()] = value.strip()
151
- else:
152
- current_property_class_header[line.strip()] = None
153
- continue
154
-
155
- if line == 'TFACE':
156
- in_tface = True
157
- continue
158
-
159
- if in_tface:
160
- if line.startswith('VRTX') or line.startswith('PVRTX'):
161
- # Parse vertex line
162
- parts = line.split()
163
- if len(parts) >= 5:
164
- _, vid, x, y, z = parts[:5]
165
- vid = int(vid)
166
- x, y, z = float(x), float(y), float(z)
167
- vertex_indices.append(vid)
168
- vertex_list.append([x, y, z])
169
- vid_to_index[vid] = len(vertex_list) - 1
170
- # If PVRTX then there could be more columns with property values. For now, we are just parsing the vertex coordinates.
171
- continue
172
- elif line.startswith('ATOM'):
173
- # Parse ATOM line
174
- parts = line.split()
175
- if len(parts) == 3:
176
- _, vid, ref_vid = parts
177
- vid = int(vid)
178
- ref_vid = int(ref_vid)
179
- if ref_vid in vid_to_index:
180
- ref_index = vid_to_index[ref_vid]
181
- coord = vertex_list[ref_index]
182
- vertex_indices.append(vid)
183
- vertex_list.append(coord)
184
- vid_to_index[vid] = len(vertex_list) - 1
185
- else:
186
- warnings.warn(f"Reference vertex {ref_vid} not found for ATOM {vid}")
187
- continue
188
- elif line.startswith('TRGL'):
189
- # Parse triangle line
190
- parts = line.split()
191
- if len(parts) == 4:
192
- _, v1, v2, v3 = parts
193
- elif len(parts) == 3:
194
- v1, v2, v3 = parts
195
- else:
196
- continue
197
- triangle_list.append([int(v1), int(v2), int(v3)])
198
- continue
199
- elif line.startswith('BSTONE'):
200
- _, value = line.split()
201
- mesh.bstones.append(int(value))
202
- continue
203
- elif line.startswith('BORDER'):
204
- parts = line.split()
205
- if len(parts) >= 4:
206
- _, bid, v1, v2 = parts[:4]
207
- mesh.borders.append({'id': int(bid), 'v1': int(v1), 'v2': int(v2)})
208
- continue
209
- elif line == 'END':
210
- in_tface = False
211
- continue
212
- else:
213
- pass
214
- continue
215
-
216
- # Other lines, possibly store as metadata
217
- if line:
218
- key_value = line.split(':', 1)
219
- if len(key_value) == 2:
220
- key, value = key_value
221
- mesh.metadata[key.strip()] = value.strip()
222
- else:
223
- pass
224
-
225
- # Convert lists to NumPy arrays
226
- mesh.vertices = np.array(vertex_list)
227
- mesh.vertex_indices = np.array(vertex_indices)
228
- mesh.edges = np.array(triangle_list)
229
-
230
- # Check the number of vertices, indices, and triangles to avoid errors (optional)
231
-
232
- return mesh
1
+ import re
2
+ import warnings
3
+ from typing import Optional, TextIO
4
+ import numpy as np
5
+ from subsurface.core.structs import UnstructuredData
6
+ from ._GOCAD_mesh import GOCADMesh
7
+
8
+
9
+ def mx_to_unstruc_from_binary(stream: TextIO) -> UnstructuredData:
10
+ content = stream.read()
11
+ goCADMeshes = _parse_lines(content)
12
+ unstruct_data = _meshes_to_unstruct(goCADMeshes)
13
+ return unstruct_data
14
+
15
+
16
+ def mx_to_unstruct_from_file(filename: str) -> UnstructuredData:
17
+ # Split the file into meshes
18
+ with open(filename, 'r') as f:
19
+ content: str = f.read()
20
+ goCAD_meshes = _parse_lines(content)
21
+ unstruct_data = _meshes_to_unstruct(goCAD_meshes)
22
+
23
+ return unstruct_data
24
+
25
+
26
+ def _parse_lines(content: str) -> list[GOCADMesh]:
27
+ meshes = []
28
+ mesh_blocks = re.split(r'(?=GOCAD TSurf 1)', content)
29
+ # Remove any empty strings from the list
30
+
31
+ mesh_blocks = [block for block in mesh_blocks if block.strip()]
32
+ # Use multiprocessing Pool to parse meshes in parallel
33
+ # with Pool(processes=cpu_count()) as pool:
34
+ # meshes = pool.map(process_mesh, mesh_blocks)
35
+ for mesh_block in mesh_blocks:
36
+ mesh_lines = mesh_block.split('\n')
37
+ mesh = _process_mesh(mesh_lines)
38
+ if mesh:
39
+ meshes.append(mesh)
40
+ return meshes
41
+
42
+
43
+ def _meshes_to_unstruct(meshes: list[GOCADMesh]) -> UnstructuredData:
44
+ # ? I added this function to the Solutions class
45
+ n_meshes = len(meshes)
46
+
47
+ vertex_array = np.concatenate([meshes[i].vertices for i in range(n_meshes)])
48
+ simplex_array = np.concatenate([meshes[i].vectorized_edges for i in range(n_meshes)])
49
+ unc, count = np.unique(simplex_array, axis=0, return_counts=True)
50
+
51
+ # * Prepare the simplex array
52
+ simplex_array = meshes[0].vectorized_edges
53
+ adder = 0
54
+ for i in range(1, n_meshes):
55
+ adder += np.max(meshes[i - 1].vectorized_edges) + 1
56
+ add_mesh = meshes[i].vectorized_edges + adder
57
+ simplex_array = np.append(simplex_array, add_mesh, axis=0)
58
+
59
+ # * Prepare the cells_attr array
60
+ ids_array = np.ones(simplex_array.shape[0])
61
+ l0 = 0
62
+ id = 1
63
+ for mesh in meshes:
64
+ l1 = l0 + mesh.vectorized_edges.shape[0]
65
+ ids_array[l0:l1] = id
66
+ l0 = l1
67
+ id += 1
68
+
69
+ # * Create the unstructured data
70
+ import pandas as pd
71
+ unstructured_data = UnstructuredData.from_array(
72
+ vertex=vertex_array,
73
+ cells=simplex_array,
74
+ cells_attr=pd.DataFrame(ids_array, columns=['id']) # TODO: We have to create an array with the shape of simplex array with the id of each simplex
75
+ )
76
+
77
+ return unstructured_data
78
+
79
+
80
+ def _process_mesh(mesh_lines) -> Optional[GOCADMesh]:
81
+ mesh = GOCADMesh()
82
+ in_header = False
83
+ in_coord_sys = False
84
+ in_property_class_header = False
85
+ in_tface = False
86
+ current_property_class_header = {}
87
+ vertex_list = []
88
+ vertex_indices = []
89
+ triangle_list = []
90
+ vid_to_index = {} # Map from vertex id to index in vertex_list
91
+
92
+ for line in mesh_lines:
93
+ line = line.strip()
94
+
95
+ if line.startswith('HEADER {'):
96
+ in_header = True
97
+ continue
98
+
99
+ if in_header:
100
+ if line == '}':
101
+ in_header = False
102
+ else:
103
+ key_value = line.split(':', 1)
104
+ if len(key_value) == 2:
105
+ key, value = key_value
106
+ mesh.header[key.strip()] = value.strip()
107
+ else:
108
+ parts = line.split()
109
+ if len(parts) == 2:
110
+ key, value = parts
111
+ mesh.header[key.strip()] = value.strip()
112
+ else:
113
+ mesh.header[line.strip()] = None
114
+ continue
115
+
116
+ if line.startswith('GOCAD_ORIGINAL_COORDINATE_SYSTEM'):
117
+ in_coord_sys = True
118
+ continue
119
+ if in_coord_sys:
120
+ if line == 'END_ORIGINAL_COORDINATE_SYSTEM':
121
+ in_coord_sys = False
122
+ else:
123
+ key_value = line.split(' ', 1)
124
+ if len(key_value) == 2:
125
+ key, value = key_value
126
+ mesh.coordinate_system[key.strip()] = value.strip()
127
+ else:
128
+ mesh.coordinate_system[line.strip()] = None
129
+ continue
130
+
131
+ if line.startswith('PROPERTY_CLASS_HEADER'):
132
+ in_property_class_header = True
133
+ current_property_class_header = {'name': line[len('PROPERTY_CLASS_HEADER'):].strip()}
134
+ continue
135
+
136
+ if in_property_class_header:
137
+ if line == '}':
138
+ in_property_class_header = False
139
+ mesh.property_class_headers.append(current_property_class_header)
140
+ current_property_class_header = {}
141
+ else:
142
+ key_value = line.split(':', 1)
143
+ if len(key_value) == 2:
144
+ key, value = key_value
145
+ current_property_class_header[key.strip()] = value.strip()
146
+ else:
147
+ key_value = line.split(' ', 1)
148
+ if len(key_value) == 2:
149
+ key, value = key_value
150
+ current_property_class_header[key.strip()] = value.strip()
151
+ else:
152
+ current_property_class_header[line.strip()] = None
153
+ continue
154
+
155
+ if line == 'TFACE':
156
+ in_tface = True
157
+ continue
158
+
159
+ if in_tface:
160
+ if line.startswith('VRTX') or line.startswith('PVRTX'):
161
+ # Parse vertex line
162
+ parts = line.split()
163
+ if len(parts) >= 5:
164
+ _, vid, x, y, z = parts[:5]
165
+ vid = int(vid)
166
+ x, y, z = float(x), float(y), float(z)
167
+ vertex_indices.append(vid)
168
+ vertex_list.append([x, y, z])
169
+ vid_to_index[vid] = len(vertex_list) - 1
170
+ # If PVRTX then there could be more columns with property values. For now, we are just parsing the vertex coordinates.
171
+ continue
172
+ elif line.startswith('ATOM'):
173
+ # Parse ATOM line
174
+ parts = line.split()
175
+ if len(parts) == 3:
176
+ _, vid, ref_vid = parts
177
+ vid = int(vid)
178
+ ref_vid = int(ref_vid)
179
+ if ref_vid in vid_to_index:
180
+ ref_index = vid_to_index[ref_vid]
181
+ coord = vertex_list[ref_index]
182
+ vertex_indices.append(vid)
183
+ vertex_list.append(coord)
184
+ vid_to_index[vid] = len(vertex_list) - 1
185
+ else:
186
+ warnings.warn(f"Reference vertex {ref_vid} not found for ATOM {vid}")
187
+ continue
188
+ elif line.startswith('TRGL'):
189
+ # Parse triangle line
190
+ parts = line.split()
191
+ if len(parts) == 4:
192
+ _, v1, v2, v3 = parts
193
+ elif len(parts) == 3:
194
+ v1, v2, v3 = parts
195
+ else:
196
+ continue
197
+ triangle_list.append([int(v1), int(v2), int(v3)])
198
+ continue
199
+ elif line.startswith('BSTONE'):
200
+ _, value = line.split()
201
+ mesh.bstones.append(int(value))
202
+ continue
203
+ elif line.startswith('BORDER'):
204
+ parts = line.split()
205
+ if len(parts) >= 4:
206
+ _, bid, v1, v2 = parts[:4]
207
+ mesh.borders.append({'id': int(bid), 'v1': int(v1), 'v2': int(v2)})
208
+ continue
209
+ elif line == 'END':
210
+ in_tface = False
211
+ continue
212
+ else:
213
+ pass
214
+ continue
215
+
216
+ # Other lines, possibly store as metadata
217
+ if line:
218
+ key_value = line.split(':', 1)
219
+ if len(key_value) == 2:
220
+ key, value = key_value
221
+ mesh.metadata[key.strip()] = value.strip()
222
+ else:
223
+ pass
224
+
225
+ # Convert lists to NumPy arrays
226
+ mesh.vertices = np.array(vertex_list)
227
+ mesh.vertex_indices = np.array(vertex_indices)
228
+ mesh.edges = np.array(triangle_list)
229
+
230
+ # Check the number of vertices, indices, and triangles to avoid errors (optional)
231
+
232
+ return mesh
@@ -1,53 +1,53 @@
1
- from typing import Union, TextIO
2
- import io
3
-
4
- from ._trimesh_reader import load_with_trimesh, trimesh_to_unstruct, TriMeshReaderFromBlob, TriMeshTransformations
5
- from ....core.structs import TriSurf
6
-
7
-
8
-
9
- def load_obj_with_trimesh_from_binary(obj_stream: TextIO, mtl_stream: list[TextIO],
10
- texture_stream: list[io.BytesIO], coord_system: TriMeshTransformations) -> TriSurf:
11
- tri_surf: TriSurf = TriMeshReaderFromBlob.OBJ_stream_to_trisurf(
12
- obj_stream=obj_stream,
13
- mtl_stream=mtl_stream,
14
- texture_stream=texture_stream,
15
- coord_system=coord_system
16
- )
17
-
18
- return tri_surf
19
-
20
-
21
- def load_obj_with_trimesh(path_to_obj: str, plot: bool = False) -> TriSurf:
22
- """
23
- Load and process an OBJ file, returning trimesh-compatible objects.
24
-
25
- This function loads an OBJ file using `trimesh`, optionally plots it,
26
- and converts the loaded mesh or scene into a suitable unstructured format
27
- using the `trimesh_to_unstruct` function. Depending on the input and the
28
- contents of the OBJ file, it may return a Trimesh object or a Scene object.
29
-
30
- Note:
31
- This implementation does not include the capability to force a PNG as a
32
- texture if the material does not already have an associated image.
33
- `trimesh` ignores UVs when this condition occurs. Modifications to
34
- `trimesh`'s loading function would be necessary to address this limitation.
35
-
36
- Args:
37
- path_to_obj: Path to the OBJ file to be loaded.
38
- This must be a valid file path to a 3D object in OBJ format.
39
- plot: Boolean flag indicating whether to visually plot the loaded model.
40
- Defaults to False.
41
-
42
- Returns:
43
- A `trimesh.Trimesh` object if a single mesh is loaded, or a `trimesh.Scene`
44
- object if the file contains multiple meshes or a scene.
45
-
46
- Raises:
47
- `FileNotFoundError`: If the provided file path does not exist.
48
- `ValueError`: If the OBJ file could not be properly processed.
49
-
50
- """
51
- trimesh = load_with_trimesh(path_to_obj, file_type="obj", plot=plot)
52
- trisurf = trimesh_to_unstruct(trimesh)
53
- return trisurf
1
+ from typing import Union, TextIO
2
+ import io
3
+
4
+ from ._trimesh_reader import load_with_trimesh, trimesh_to_unstruct, TriMeshReaderFromBlob, TriMeshTransformations
5
+ from ....core.structs import TriSurf
6
+
7
+
8
+
9
+ def load_obj_with_trimesh_from_binary(obj_stream: TextIO, mtl_stream: list[TextIO],
10
+ texture_stream: list[io.BytesIO], coord_system: TriMeshTransformations) -> TriSurf:
11
+ tri_surf: TriSurf = TriMeshReaderFromBlob.OBJ_stream_to_trisurf(
12
+ obj_stream=obj_stream,
13
+ mtl_stream=mtl_stream,
14
+ texture_stream=texture_stream,
15
+ coord_system=coord_system
16
+ )
17
+
18
+ return tri_surf
19
+
20
+
21
+ def load_obj_with_trimesh(path_to_obj: str, plot: bool = False) -> TriSurf:
22
+ """
23
+ Load and process an OBJ file, returning trimesh-compatible objects.
24
+
25
+ This function loads an OBJ file using `trimesh`, optionally plots it,
26
+ and converts the loaded mesh or scene into a suitable unstructured format
27
+ using the `trimesh_to_unstruct` function. Depending on the input and the
28
+ contents of the OBJ file, it may return a Trimesh object or a Scene object.
29
+
30
+ Note:
31
+ This implementation does not include the capability to force a PNG as a
32
+ texture if the material does not already have an associated image.
33
+ `trimesh` ignores UVs when this condition occurs. Modifications to
34
+ `trimesh`'s loading function would be necessary to address this limitation.
35
+
36
+ Args:
37
+ path_to_obj: Path to the OBJ file to be loaded.
38
+ This must be a valid file path to a 3D object in OBJ format.
39
+ plot: Boolean flag indicating whether to visually plot the loaded model.
40
+ Defaults to False.
41
+
42
+ Returns:
43
+ A `trimesh.Trimesh` object if a single mesh is loaded, or a `trimesh.Scene`
44
+ object if the file contains multiple meshes or a scene.
45
+
46
+ Raises:
47
+ `FileNotFoundError`: If the provided file path does not exist.
48
+ `ValueError`: If the OBJ file could not be properly processed.
49
+
50
+ """
51
+ trimesh = load_with_trimesh(path_to_obj, file_type="obj", plot=plot)
52
+ trisurf = trimesh_to_unstruct(trimesh)
53
+ return trisurf
@@ -1,43 +1,43 @@
1
- import io
2
-
3
- import numpy as np
4
-
5
- import subsurface
6
- from ....optional_requirements import require_omf, require_pyvista
7
- from ....core.structs.base_structures import UnstructuredData
8
-
9
-
10
- def omf_stream_to_unstructs(stream: io.BytesIO) -> list[UnstructuredData]:
11
- pyvista = require_pyvista()
12
- omfvista = require_omf()
13
- omf = omfvista.load_project(stream)
14
-
15
- all_vertex = []
16
- all_cells = []
17
- cell_attr = []
18
- _last_cell: int = 0
19
-
20
- for i in range(omf.n_blocks):
21
- block: pyvista.PolyData = omf[i]
22
- cell_type = block.get_cell(0).type
23
-
24
- if cell_type == pyvista.CellType.TRIANGLE:
25
- pyvista_unstructured_grid: pyvista.UnstructuredGrid = block.cast_to_unstructured_grid()
26
- all_vertex.append(pyvista_unstructured_grid.points)
27
- cells: np.ndarray = pyvista_unstructured_grid.cells.reshape(-1, 4)[:, 1:]
28
- if len(all_cells) > 0:
29
- cells = cells + _last_cell
30
-
31
- all_cells.append(cells)
32
- cell_attr.append(np.ones(len(all_cells[-1])) * i)
33
- _last_cell = cells.max() + 1
34
-
35
- # * Create the unstructured data
36
- import pandas as pd
37
-
38
- unstructured_data = subsurface.UnstructuredData.from_array(
39
- vertex=np.vstack(all_vertex),
40
- cells=np.vstack(all_cells),
41
- cells_attr=pd.DataFrame(np.hstack(cell_attr), columns=["Block id"]),
42
- )
43
- return [unstructured_data]
1
+ import io
2
+
3
+ import numpy as np
4
+
5
+ import subsurface
6
+ from ....optional_requirements import require_omf, require_pyvista
7
+ from ....core.structs.base_structures import UnstructuredData
8
+
9
+
10
+ def omf_stream_to_unstructs(stream: io.BytesIO) -> list[UnstructuredData]:
11
+ pyvista = require_pyvista()
12
+ omfvista = require_omf()
13
+ omf = omfvista.load_project(stream)
14
+
15
+ all_vertex = []
16
+ all_cells = []
17
+ cell_attr = []
18
+ _last_cell: int = 0
19
+
20
+ for i in range(omf.n_blocks):
21
+ block: pyvista.PolyData = omf[i]
22
+ cell_type = block.get_cell(0).type
23
+
24
+ if cell_type == pyvista.CellType.TRIANGLE:
25
+ pyvista_unstructured_grid: pyvista.UnstructuredGrid = block.cast_to_unstructured_grid()
26
+ all_vertex.append(pyvista_unstructured_grid.points)
27
+ cells: np.ndarray = pyvista_unstructured_grid.cells.reshape(-1, 4)[:, 1:]
28
+ if len(all_cells) > 0:
29
+ cells = cells + _last_cell
30
+
31
+ all_cells.append(cells)
32
+ cell_attr.append(np.ones(len(all_cells[-1])) * i)
33
+ _last_cell = cells.max() + 1
34
+
35
+ # * Create the unstructured data
36
+ import pandas as pd
37
+
38
+ unstructured_data = subsurface.UnstructuredData.from_array(
39
+ vertex=np.vstack(all_vertex),
40
+ cells=np.vstack(all_cells),
41
+ cells_attr=pd.DataFrame(np.hstack(cell_attr), columns=["Block id"]),
42
+ )
43
+ return [unstructured_data]