Handling complex boundaries on a Cartesian grid using surface singularities