def normal(self, surface_point: tuple) -> tuple: on_surf, surf_indexes = on_aabb_surface(self._size, surface_point, atol=2*EPS_ZERO) if not on_surf: raise GeometryError( "Point is not on surface.", {"point": surface_point, "geometry": self} ) if len(surf_indexes) != 1: raise GeometryError( "Point is on multiple surfaces.", {"point": surface_point, "geometry": self} ) idx = surf_indexes[0] # normal vector in the local frame return NORMALS[idx]
def normal(self, surface_point: tuple) -> tuple: """ Returns the unit surface normal at the surface_point. """ mesh = self.trimesh (closest_points, distances, triangle_id) = mesh.nearest.on_surface(np.array([surface_point])) if closest_points.shape != (1, 3): raise GeometryError( 'Mesh must have a single closest point to calculate normal.') if not np.any(np.absolute(distances) < EPS_ZERO): raise GeometryError( 'Point is not on surface.', { "point": surface_point, "geometry": self, "distances": distances, "threshold": EPS_ZERO }) normal = tuple(mesh.face_normals[triangle_id[0]]) return normal
def is_entering(self, surface_point, direction) -> bool: """ Returns True if the ray at surface point with direction is heading into the shape. This is tested by checking for a negative dot product between the vectors. """ if not self.is_on_surface(surface_point): raise GeometryError("Not a surface point.") normal = self.normal(surface_point) if np.dot(normal, direction) < 0.0: return True return False
def normal(self, surface_point): """ Normal faces outwards by convention. """ z = surface_point[2] if np.isclose(z, -0.5 * self.length): return (0.0, 0.0, -1.0) elif np.isclose(z, 0.5 * self.length): return (0.0, 0.0, 1.0) elif np.isclose(self.radius, np.sqrt(np.sum(np.array(surface_point[:2]) ** 2))): v = np.array(surface_point) - np.array([0.0, 0.0, surface_point[2]]) n = tuple(norm(v).tolist()) return n else: raise GeometryError("Not a surface point.")