How about this for the first phase? I think you can imagine how the rest goes, more later...
Mapper 1A. map() input: One canopy map() output: canopy ID -> canopy Mapper 1B. Has in memory all canopy IDs, read at startup) map() input: one point map() output: for each canopy ID, canopy ID -> point Reducer 1. reduce() input: canopy ID mapped to many points, one canopy reduce() output: for each point, compute distance from point to canopy, output (canopy ID, point ID) -> distance