(self, location: Tensor)
| 226 | |
| 227 | @staticmethod |
| 228 | def _closest_surface(self, location: Tensor): |
| 229 | on_skeleton, uv, unbounded_uv, tangents = closest_param(self.order, self.points, location, uv_gradient=False) |
| 230 | delta = location - on_skeleton |
| 231 | normal_c = vec_normalize(cross(*tangents.tangents.dual)) |
| 232 | thickness = self.thickness_at(uv) |
| 233 | radius = .5 * thickness |
| 234 | # --- Compute effective fillet (1 inside valid uv range) --- |
| 235 | is_edge = stack({'-': unbounded_uv < uv, '+': unbounded_uv > uv}, '~side') |
| 236 | fillets = stack({dim: stack({'-': self.fillet[dim+'-'], '+': self.fillet[dim+'+']}, '~side') for dim in spatial(self.points).names}, 'spline:c') |
| 237 | fillet = where(is_edge, fillets, 1) |
| 238 | h = normal_c.vector @ delta |
| 239 | is_corner = math.sum(is_edge, 'spline,~side') >= 2 |
| 240 | # --- Corner: Constrain sphere center to plane orthogonal to large fillet --- |
| 241 | large_fillet = math.max(fillets * is_edge, '~side,spline') |
| 242 | small_fillet = math.min(fillet, '~side,spline') |
| 243 | large_fillet_tangent = math.min(tangents, '~tangents', key=dsum(fillet * is_edge).spline.as_dual('tangents')) |
| 244 | ortho_dir = vec_normalize(cross(normal_c, large_fillet_tangent)) |
| 245 | w = ortho_dir.vector @ (location - on_skeleton) |
| 246 | safe_h = radius * (1 - large_fillet) |
| 247 | # ToDo need safe_w after all |
| 248 | h_over = maximum(0, abs(h) - safe_h) * sign(h) |
| 249 | over = clip_length(vec('dir', w=w, h=h_over), max_len=radius * (large_fillet - small_fillet), vec_dim='dir') |
| 250 | wh = vec('dir', w=0, h=clip(h, -safe_h, safe_h)) + over |
| 251 | dirs = stack({'w': ortho_dir, 'h': normal_c}, '~dir') |
| 252 | c_sphere_offset = dirs @ wh |
| 253 | c_sphere_rad = radius * small_fillet |
| 254 | # --- Edge/segment: Constrain sphere center to line orthogonal to spline skeleton --- |
| 255 | sphere_rad = radius * dmin(fillet.spline.as_dual('tangents')) |
| 256 | sphere_h_lim = radius - sphere_rad |
| 257 | sphere_h = clip(h, -sphere_h_lim, sphere_h_lim) |
| 258 | sphere_offset = normal_c * sphere_h |
| 259 | # --- Construct sphere --- |
| 260 | sphere_offset = where(is_corner, c_sphere_offset, sphere_offset) |
| 261 | sphere_rad = where(is_corner, c_sphere_rad, sphere_rad) |
| 262 | sphere = Sphere(center=on_skeleton + sphere_offset, radius=sphere_rad) |
| 263 | face_index = vec('index', **to_int32(clip(unbounded_uv+1, 0, self.resolution)).spline, **{'~side': to_int32(h <= 0)}) |
| 264 | def sphere_sdf(sphere: Sphere, location: Tensor): |
| 265 | return sphere.approximate_closest_surface(location) |
| 266 | sdf, delta, normal, offset, _ = map_types(sphere_sdf, instance(location), batch)(sphere, location) |
| 267 | return sdf, delta, normal, offset, face_index, on_skeleton, uv, unbounded_uv, tangents, normal_c, thickness, is_edge, is_corner |
| 268 | |
| 269 | def thickness_at(self, uv: Tensor): |
| 270 | if not spatial(self.thickness): |
no test coverage detected