1- from typing import List
1+ from typing import List , Dict , Optional
22
33import numpy as np
44
88
99def _apply_fault_relations_to_overlaps (
1010 all_meshes : List [DualContouringMesh ],
11- voxel_overlaps : dict ,
11+ voxel_overlaps : Dict [ str , dict ] ,
1212 stacks_structure : StacksStructure
1313) -> None :
1414 """
1515 Apply fault relations to voxel overlaps by updating mesh vertices.
1616
1717 Args:
1818 all_meshes: List of dual contouring meshes
19- faults_relations: Boolean matrix indicating fault relationships between stacks
2019 voxel_overlaps: Dictionary containing overlap information between stacks
21- n_stacks: Total number of stacks
20+ stacks_structure: Structure containing fault relations and stack information
2221 """
23- faults_relations = stacks_structure .faults_relations
24- n_stacks = stacks_structure .n_stacks
25- number_surfaces_per_stack = stacks_structure .number_of_surfaces_per_stack_vector
26-
27- if faults_relations is None :
22+ if stacks_structure .faults_relations is None :
2823 return
2924
30- # Iterate through fault relations matrix
25+ faults_relations = stacks_structure .faults_relations
26+ n_stacks = stacks_structure .n_stacks
27+ surfaces_per_stack = stacks_structure .number_of_surfaces_per_stack_vector
28+
29+ # Process fault relations
30+ for origin_stack , destination_stack in _get_fault_pairs (faults_relations , n_stacks ):
31+ surface_range = _get_surface_range (surfaces_per_stack , destination_stack )
32+
33+ for surface_n in surface_range :
34+ overlap_key = f"stack_{ origin_stack } _vs_stack_{ surface_n } "
35+
36+ if overlap_key in voxel_overlaps :
37+ _apply_vertex_sharing (
38+ all_meshes ,
39+ origin_stack ,
40+ surface_n ,
41+ voxel_overlaps [overlap_key ]
42+ )
43+
44+
45+ def _get_fault_pairs (faults_relations : np .ndarray , n_stacks : int ):
46+ """Generate pairs of stacks that have fault relations."""
3147 for origin_stack in range (n_stacks ):
3248 for destination_stack in range (n_stacks ):
3349 if faults_relations [origin_stack , destination_stack ]:
34- for surface_n in range ( number_surfaces_per_stack [ destination_stack ], number_surfaces_per_stack [ destination_stack + 1 ]):
35- overlap_key = f"stack_ { origin_stack } _vs_stack_ { surface_n } "
50+ yield origin_stack , destination_stack
51+
3652
37- # Check if there are actual overlaps between these stacks
38- if overlap_key in voxel_overlaps :
39- _apply_vertex_sharing (all_meshes , origin_stack , surface_n , voxel_overlaps [overlap_key ])
53+ def _get_surface_range (surfaces_per_stack : np .ndarray , stack_index : int ) -> range :
54+ """Get the range of surfaces for a given stack."""
55+ return range (
56+ surfaces_per_stack [stack_index ],
57+ surfaces_per_stack [stack_index + 1 ]
58+ )
4059
4160
4261def _apply_vertex_sharing (
4362 all_meshes : List [DualContouringMesh ],
44- origin_mesh : int ,
45- destination_mesh : int ,
63+ origin_mesh_idx : int ,
64+ destination_mesh_idx : int ,
4665 overlap_data : dict
4766) -> None :
4867 """
4968 Apply vertex sharing between origin and destination meshes based on overlap data.
5069
5170 Args:
5271 all_meshes: List of dual contouring meshes
53- origin_mesh: Stack index that serves as the source of vertices
54- destination_mesh: Stack index that receives vertices from origin
72+ origin_mesh_idx: Index of mesh that serves as the source of vertices
73+ destination_mesh_idx: Index of mesh that receives vertices from origin
5574 overlap_data: Dictionary containing indices and overlap information
56- mesh_indices_offset: Starting mesh index for each stack
5775 """
58- # origin_mesh_idx = mesh_indices_offset[origin_stack]
59- # destination_mesh_idx = mesh_indices_offset[destination_stack]
60- origin_mesh_idx = origin_mesh
61- destination_mesh_idx = destination_mesh
62-
63- # Ensure mesh indices are valid
64- if origin_mesh_idx >= len (all_meshes ) or destination_mesh_idx >= len (all_meshes ):
76+ if not _are_valid_mesh_indices (all_meshes , origin_mesh_idx , destination_mesh_idx ):
6577 return
6678
67- # Apply the vertex sharing (same logic as original _f function)
6879 origin_mesh = all_meshes [origin_mesh_idx ]
6980 destination_mesh = all_meshes [destination_mesh_idx ]
7081
71- indices_in_origin = overlap_data ["indices_in_stack_i" ]
72- indices_in_destination = overlap_data ["indices_in_stack_j" ]
82+ # Share vertices from origin to destination
83+ origin_indices = overlap_data ["indices_in_stack_i" ]
84+ destination_indices = overlap_data ["indices_in_stack_j" ]
85+
86+ destination_mesh .vertices [destination_indices ] = origin_mesh .vertices [origin_indices ]
87+
7388
74- destination_mesh .vertices [indices_in_destination ] = origin_mesh .vertices [indices_in_origin ]
89+ def _are_valid_mesh_indices (all_meshes : List [DualContouringMesh ], * indices : int ) -> bool :
90+ """Check if all provided mesh indices are valid."""
91+ return all (0 <= idx < len (all_meshes ) for idx in indices )
7592
7693
77- def find_repeated_voxels_across_stacks (all_left_right_codes : List [np .ndarray ]) -> dict :
94+ def find_repeated_voxels_across_stacks (all_left_right_codes : List [np .ndarray ]) -> Dict [ str , dict ] :
7895 """
79- Find repeated voxels using NumPy operations - better for very large arrays.
96+ Find repeated voxels using NumPy operations for efficient processing of large arrays.
8097
8198 Args:
8299 all_left_right_codes: List of left_right_codes arrays, one per stack
83100
84101 Returns:
85- Dictionary with detailed overlap analysis
102+ Dictionary with detailed overlap analysis between stack pairs
86103 """
87-
88104 if not all_left_right_codes :
89105 return {}
90106
91- # Generate voxel codes for each stack
107+ stack_codes = _generate_voxel_codes (all_left_right_codes )
108+ return _find_overlaps_between_stacks (stack_codes , all_left_right_codes )
109+
92110
111+ def _generate_voxel_codes (all_left_right_codes : List [np .ndarray ]) -> List [np .ndarray ]:
112+ """Generate voxel codes for each stack using packed bit directions."""
93113 from gempy_engine .modules .dual_contouring .fancy_triangulation import _StaticTriangulationData
114+
115+ pack_directions = _StaticTriangulationData .get_pack_directions_into_bits ()
94116 stack_codes = []
117+
95118 for left_right_codes in all_left_right_codes :
96119 if left_right_codes .size > 0 :
97- voxel_codes = (left_right_codes * _StaticTriangulationData . get_pack_directions_into_bits () ).sum (axis = 1 )
120+ voxel_codes = (left_right_codes * pack_directions ).sum (axis = 1 )
98121 stack_codes .append (voxel_codes )
99122 else :
100123 stack_codes .append (np .array ([]))
124+
125+ return stack_codes
101126
102- overlaps = {}
103127
104- # Check each pair of stacks
128+ def _find_overlaps_between_stacks (
129+ stack_codes : List [np .ndarray ],
130+ all_left_right_codes : List [np .ndarray ]
131+ ) -> Dict [str , dict ]:
132+ """Find overlaps between all pairs of stacks."""
133+ overlaps = {}
134+
105135 for i in range (len (stack_codes )):
106136 for j in range (i + 1 , len (stack_codes )):
107- if stack_codes [i ].size == 0 or stack_codes [j ].size == 0 :
108- continue
109-
110- # Find common voxel codes using numpy
111- common_codes = np .intersect1d (stack_codes [i ], stack_codes [j ])
112-
113- if len (common_codes ) > 0 :
114- # Get indices of common voxels in each stack
115- indices_i = np .isin (stack_codes [i ], common_codes )
116- indices_j = np .isin (stack_codes [j ], common_codes )
117-
118- overlaps [f"stack_{ i } _vs_stack_{ j } " ] = {
119- 'common_voxel_codes' : common_codes ,
120- 'count' : len (common_codes ),
121- 'indices_in_stack_i' : np .where (indices_i )[0 ],
122- 'indices_in_stack_j' : np .where (indices_j )[0 ],
123- 'common_binary_codes_i' : all_left_right_codes [i ][indices_i ],
124- 'common_binary_codes_j' : all_left_right_codes [j ][indices_j ]
125- }
126-
137+ overlap_data = _process_stack_pair (
138+ stack_codes [i ], stack_codes [j ],
139+ all_left_right_codes [i ], all_left_right_codes [j ],
140+ i , j
141+ )
142+
143+ if overlap_data :
144+ overlaps [f"stack_{ i } _vs_stack_{ j } " ] = overlap_data
145+
127146 return overlaps
147+
148+
149+ def _process_stack_pair (
150+ codes_i : np .ndarray ,
151+ codes_j : np .ndarray ,
152+ left_right_i : np .ndarray ,
153+ left_right_j : np .ndarray ,
154+ stack_i : int ,
155+ stack_j : int
156+ ) -> Optional [dict ]:
157+ """Process a pair of stacks to find overlapping voxels."""
158+ if codes_i .size == 0 or codes_j .size == 0 :
159+ return None
160+
161+ common_codes = np .intersect1d (codes_i , codes_j )
162+
163+ if len (common_codes ) == 0 :
164+ return None
165+
166+ # Find indices of common voxels in each stack
167+ indices_i = np .isin (codes_i , common_codes )
168+ indices_j = np .isin (codes_j , common_codes )
169+
170+ return {
171+ 'common_voxel_codes' : common_codes ,
172+ 'count' : len (common_codes ),
173+ 'indices_in_stack_i' : np .where (indices_i )[0 ],
174+ 'indices_in_stack_j' : np .where (indices_j )[0 ],
175+ 'common_binary_codes_i' : left_right_i [indices_i ],
176+ 'common_binary_codes_j' : left_right_j [indices_j ]
177+ }
0 commit comments