@mikeabuilder I don't have multiple tools, so it's simple. I never thought we can use slicer for this. In my start script, it tries different area (4 side rects) with different clearances, and calls this macro at the first suitable place. I think you may need to find a larger area so that multiple head can purge at the same time?
var min_x = ...
...
var xc = (var.min_x + var.max_x) / 2
var yc = (var.min_y + var.max_y) / 2
var clearance = 40 ; start from 40 / 2
var rect_x1 = 0
var rect_x2 = 0
var rect_y1 = 0
var rect_y2 = 0
while var.clearance > 1
if mod(iterations, 4) == 0
set var.clearance = var.clearance / 2
if var.clearance < 1
break
set var.rect_x1 = mod(iterations, 4) == 0 ? var.max_x + var.clearance : move.axes[0].min
set var.rect_x2 = mod(iterations, 4) == 1 ? var.min_x - var.clearance : move.axes[1].max
set var.rect_y1 = mod(iterations, 4) == 2 ? var.max_y + var.clearance : move.axes[2].min
set var.rect_y2 = mod(iterations, 4) == 3 ? var.min_y - var.clearance : move.axes[2].max
if var.rect_x1 + global.NOZZLE_DIAMETER > var.rect_x2
continue
if var.rect_y1 + global.NOZZLE_DIAMETER > var.rect_y2
continue
if (var.rect_x2 - var.rect_x1) * (var.rect_y2 - var.rect_y1) < var.purge_area
continue
; Project (xc, yc) into the rect
set var.xc = min(max(var.xc, var.rect_x1), var.rect_x2)
set var.yc = min(max(var.yc, var.rect_y1), var.rect_y2)
; Shrink the rect to purge_area, close to (xc, yc) and close to a square
var xl = max(sqrt(var.purge_area), var.purge_area / (var.rect_y2 - var.rect_y1))
var yl = var.purge_area / var.xl
set var.rect_x1 = max(min(var.xc - var.xl / 2, var.rect_x2 - var.xl), var.rect_x1)
set var.rect_x2 = var.rect_x1 + var.xl
set var.rect_y1 = max(min(var.yc - var.yl / 2, var.rect_y2 - var.yl), var.rect_y1)
set var.rect_y2 = var.rect_y1 + var.yl
echo "Purge in the rect " ^ {var.rect_x1, var.rect_x2, var.rect_y1, var.rect_y2}
M98 P"0:/macros/purge_rect.g" A{var.rect_x1} B{var.rect_x2} C{var.rect_y1} D{var.rect_y2}
break
if var.clearance < 1
echo "no place to purge"