subsurface-terra 2025.1.0rc14__py3-none-any.whl → 2025.1.0rc16__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 (81) 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 -0
  9. subsurface/core/geological_formats/boreholes/_survey_to_unstruct.py +163 -0
  10. subsurface/core/geological_formats/boreholes/boreholes.py +140 -116
  11. subsurface/core/geological_formats/boreholes/collars.py +26 -26
  12. subsurface/core/geological_formats/boreholes/survey.py +86 -380
  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/_liquid_earth_mesh.py +121 -121
  20. subsurface/core/structs/base_structures/_unstructured_data_constructor.py +70 -70
  21. subsurface/core/structs/base_structures/base_structures_enum.py +6 -6
  22. subsurface/core/structs/base_structures/structured_data.py +282 -282
  23. subsurface/core/structs/base_structures/unstructured_data.py +319 -319
  24. subsurface/core/structs/structured_elements/octree_mesh.py +10 -10
  25. subsurface/core/structs/structured_elements/structured_grid.py +59 -59
  26. subsurface/core/structs/structured_elements/structured_mesh.py +9 -9
  27. subsurface/core/structs/unstructured_elements/__init__.py +3 -3
  28. subsurface/core/structs/unstructured_elements/line_set.py +72 -72
  29. subsurface/core/structs/unstructured_elements/point_set.py +43 -43
  30. subsurface/core/structs/unstructured_elements/tetrahedron_mesh.py +35 -35
  31. subsurface/core/structs/unstructured_elements/triangular_surface.py +62 -62
  32. subsurface/core/utils/utils_core.py +38 -38
  33. subsurface/modules/reader/__init__.py +13 -13
  34. subsurface/modules/reader/faults/faults.py +80 -80
  35. subsurface/modules/reader/from_binary.py +46 -46
  36. subsurface/modules/reader/mesh/_GOCAD_mesh.py +82 -82
  37. subsurface/modules/reader/mesh/_trimesh_reader.py +447 -447
  38. subsurface/modules/reader/mesh/csv_mesh_reader.py +53 -53
  39. subsurface/modules/reader/mesh/dxf_reader.py +177 -177
  40. subsurface/modules/reader/mesh/glb_reader.py +30 -30
  41. subsurface/modules/reader/mesh/mx_reader.py +232 -232
  42. subsurface/modules/reader/mesh/obj_reader.py +53 -53
  43. subsurface/modules/reader/mesh/omf_mesh_reader.py +43 -43
  44. subsurface/modules/reader/mesh/surface_reader.py +56 -56
  45. subsurface/modules/reader/mesh/surfaces_api.py +41 -41
  46. subsurface/modules/reader/profiles/__init__.py +3 -3
  47. subsurface/modules/reader/profiles/profiles_core.py +197 -197
  48. subsurface/modules/reader/read_netcdf.py +38 -38
  49. subsurface/modules/reader/topography/__init__.py +7 -7
  50. subsurface/modules/reader/topography/topo_core.py +100 -100
  51. subsurface/modules/reader/volume/read_grav3d.py +478 -428
  52. subsurface/modules/reader/volume/read_volume.py +327 -230
  53. subsurface/modules/reader/volume/segy_reader.py +105 -105
  54. subsurface/modules/reader/volume/seismic.py +173 -173
  55. subsurface/modules/reader/volume/volume_utils.py +43 -43
  56. subsurface/modules/reader/wells/DEP/__init__.py +43 -43
  57. subsurface/modules/reader/wells/DEP/_well_files_reader.py +167 -167
  58. subsurface/modules/reader/wells/DEP/_wells_api.py +61 -61
  59. subsurface/modules/reader/wells/DEP/_welly_reader.py +180 -180
  60. subsurface/modules/reader/wells/DEP/pandas_to_welly.py +212 -212
  61. subsurface/modules/reader/wells/_read_to_df.py +57 -57
  62. subsurface/modules/reader/wells/read_borehole_interface.py +148 -148
  63. subsurface/modules/reader/wells/wells_utils.py +68 -68
  64. subsurface/modules/tools/mocking_aux.py +104 -104
  65. subsurface/modules/visualization/__init__.py +2 -2
  66. subsurface/modules/visualization/to_pyvista.py +320 -320
  67. subsurface/modules/writer/to_binary.py +12 -12
  68. subsurface/modules/writer/to_rex/common.py +78 -78
  69. subsurface/modules/writer/to_rex/data_struct.py +74 -74
  70. subsurface/modules/writer/to_rex/gempy_to_rexfile.py +791 -791
  71. subsurface/modules/writer/to_rex/material_encoder.py +44 -44
  72. subsurface/modules/writer/to_rex/mesh_encoder.py +152 -152
  73. subsurface/modules/writer/to_rex/to_rex.py +115 -115
  74. subsurface/modules/writer/to_rex/utils.py +15 -15
  75. subsurface/optional_requirements.py +116 -116
  76. {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/METADATA +194 -194
  77. subsurface_terra-2025.1.0rc16.dist-info/RECORD +98 -0
  78. {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/WHEEL +1 -1
  79. {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.dist-info}/licenses/LICENSE +203 -203
  80. subsurface_terra-2025.1.0rc14.dist-info/RECORD +0 -96
  81. {subsurface_terra-2025.1.0rc14.dist-info → subsurface_terra-2025.1.0rc16.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]