|
1 | 1 | use super::VoxelsChunk; |
2 | | -use crate::math::{Point, Vector, DIM}; |
| 2 | +use crate::math::{Point, Real, Vector, DIM}; |
3 | 3 | use crate::shape::{VoxelState, Voxels}; |
4 | 4 |
|
5 | 5 | impl Voxels { |
@@ -139,55 +139,64 @@ impl Voxels { |
139 | 139 | /// will have coordinates `key + origin_shift` on `self`. |
140 | 140 | pub fn combine_voxel_states(&mut self, other: &mut Self, origin_shift: Vector<i32>) { |
141 | 141 | let one = Vector::repeat(1); |
142 | | - |
143 | | - // Intersect the domains + 1 cell. |
144 | | - let [my_domain_mins, my_domain_maxs] = self.domain(); |
145 | | - let [other_domain_mins, other_domain_maxs] = other.domain(); |
146 | | - let d0 = [my_domain_mins - one, my_domain_maxs + one * 2]; |
147 | | - let d1 = [ |
148 | | - other_domain_mins - one + origin_shift, |
149 | | - other_domain_maxs + one * 2 + origin_shift, |
150 | | - ]; |
151 | | - |
152 | | - let d01 = [d0[0].sup(&d1[0]), d0[1].inf(&d1[1])]; |
153 | | - // Iterate on the domain intersection. If the voxel exists (and is non-empty) on both shapes, we |
154 | | - // simply need to combine their bitmasks. If it doesn’t exist on both shapes, we need to |
155 | | - // actually check the neighbors. |
156 | | - // |
157 | | - // The `domain` is expressed in the grid coordinate space of `self`. |
158 | | - for i in d01[0].x..d01[1].x { |
159 | | - for j in d01[0].y..d01[1].y { |
160 | | - #[cfg(feature = "dim2")] |
161 | | - let k_range = 0..1; |
162 | | - #[cfg(feature = "dim3")] |
163 | | - let k_range = d01[0].z..d01[1].z; |
164 | | - for _k in k_range { |
165 | | - #[cfg(feature = "dim2")] |
166 | | - let key0 = Point::new(i, j); |
167 | | - #[cfg(feature = "dim3")] |
168 | | - let key0 = Point::new(i, j, _k); |
169 | | - let key1 = key0 - origin_shift; |
170 | | - let vox0 = self |
171 | | - .linear_index(key0) |
172 | | - .map(|id| &mut self.chunks[id.chunk_id].states[id.id_in_chunk]) |
173 | | - .filter(|state| !state.is_empty()); |
174 | | - let vox1 = other |
175 | | - .linear_index(key1) |
176 | | - .map(|id| &mut other.chunks[id.chunk_id].states[id.id_in_chunk]) |
177 | | - .filter(|state| !state.is_empty()); |
178 | | - |
179 | | - match (vox0, vox1) { |
180 | | - (Some(vox0), Some(vox1)) => { |
181 | | - vox0.0 |= vox1.0; |
182 | | - vox1.0 |= vox0.0; |
183 | | - } |
184 | | - (Some(vox0), None) => { |
185 | | - vox0.0 |= other.compute_voxel_neighborhood_bits(key1).0; |
186 | | - } |
187 | | - (None, Some(vox1)) => { |
188 | | - vox1.0 |= self.compute_voxel_neighborhood_bits(key0).0; |
| 142 | + let origin_shift_worldspace = origin_shift.cast::<Real>().component_mul(&self.voxel_size); |
| 143 | + |
| 144 | + for chunk_key in &self.chunk_keys { |
| 145 | + let mut aabb = VoxelsChunk::aabb(chunk_key, &self.voxel_size); |
| 146 | + // Enlarge by one-half voxel so we detect cases where we also detect neighbor chunks from `other`. |
| 147 | + aabb.mins -= self.voxel_size / 2.0; |
| 148 | + aabb.maxs += self.voxel_size / 2.0; |
| 149 | + // Shift to the local coordinate system of `other`. |
| 150 | + let shifted_aabb = aabb.translated(&-origin_shift_worldspace); |
| 151 | + |
| 152 | + if other.chunk_bvh.intersect_aabb(&shifted_aabb).any(|_| true) { |
| 153 | + // Check the voxels from this chunk against the other voxels shape. |
| 154 | + |
| 155 | + // Iterate on the domain intersection. If the voxel exists (and is non-empty) on both shapes, we |
| 156 | + // simply need to combine their bitmasks. If it doesn’t exist on both shapes, we need to |
| 157 | + // actually check the neighbors. |
| 158 | + // |
| 159 | + // The `domain` is expressed in the grid coordinate space of `self`. |
| 160 | + let mut domain = VoxelsChunk::keys_bounds(chunk_key); |
| 161 | + // Enlarge the domain by one voxel so that voxels from `other` but not existing in `self` are updated too. |
| 162 | + domain[0] -= one; |
| 163 | + domain[1] += one; |
| 164 | + |
| 165 | + for i in domain[0].x..domain[1].x { |
| 166 | + for j in domain[0].y..domain[1].y { |
| 167 | + #[cfg(feature = "dim2")] |
| 168 | + let k_range = 0..1; |
| 169 | + #[cfg(feature = "dim3")] |
| 170 | + let k_range = domain[0].z..domain[1].z; |
| 171 | + for _k in k_range { |
| 172 | + #[cfg(feature = "dim2")] |
| 173 | + let key0 = Point::new(i, j); |
| 174 | + #[cfg(feature = "dim3")] |
| 175 | + let key0 = Point::new(i, j, _k); |
| 176 | + let key1 = key0 - origin_shift; |
| 177 | + let vox0 = self |
| 178 | + .linear_index(key0) |
| 179 | + .map(|id| &mut self.chunks[id.chunk_id].states[id.id_in_chunk]) |
| 180 | + .filter(|state| !state.is_empty()); |
| 181 | + let vox1 = other |
| 182 | + .linear_index(key1) |
| 183 | + .map(|id| &mut other.chunks[id.chunk_id].states[id.id_in_chunk]) |
| 184 | + .filter(|state| !state.is_empty()); |
| 185 | + |
| 186 | + match (vox0, vox1) { |
| 187 | + (Some(vox0), Some(vox1)) => { |
| 188 | + vox0.0 |= vox1.0; |
| 189 | + vox1.0 |= vox0.0; |
| 190 | + } |
| 191 | + (Some(vox0), None) => { |
| 192 | + vox0.0 |= other.compute_voxel_neighborhood_bits(key1).0; |
| 193 | + } |
| 194 | + (None, Some(vox1)) => { |
| 195 | + vox1.0 |= self.compute_voxel_neighborhood_bits(key0).0; |
| 196 | + } |
| 197 | + (None, None) => { /* Nothing to adjust. */ } |
| 198 | + } |
189 | 199 | } |
190 | | - (None, None) => { /* Nothing to adjust. */ } |
191 | 200 | } |
192 | 201 | } |
193 | 202 | } |
|
0 commit comments