Search code examples
geometrymaskgoogle-earth-engine

Unexpected behaviour of geometry in Earth Engine


I am analysing solar farms and have defined two areas of geometry. In the example below, for a site called 'Stateline', I have drawn the boundary of the site and saved the geometry as a variable 'Stateline_boundary'. I have drawn around the solar panels within the boundary, which exist in two distinct groups and saved the geometry as a variable 'Stateline_panels'.

Stateline_panels has two co-ordinate lists (as there are two areas of panels).

When I try to subtract the area covered by the panels from the area within the boundary only the first of the two lists in the 'Stateline_panels' geometry is used (see code below and attached image).Mask with one of two areas of panels missing

var mask = Stateline_boundary
var mask_no_panels = mask.difference(Stateline_panels);
Map.addLayer(mask_no_panels,{},'Stateline_mask_no_panels',false);

I don't understand the behaviour of the geometry. Specifically why when adding the 'Stateline_panels' geometry to the map it displays in its entirety, but when used as a mask breaks the geometry and only uses the first of two lists of coordinates.

I was going to write a longer question asking why the geometry variables seem to behave differently when they are imported into the script rather than listed within the script (which I don't think should make a difference, but it does). However I think this is an earlier manifestation of whatever is going on.


Solution

  • The methodology that I found worked in the end was to create geometry assets individually with the polygon tool in the Earth Engine IDE - ensuring that each is on a different layer (using the line tool, then converting to polygons never worked).

    Not only was this more flexible, it was also easier to manage on Earth Engine as editing geometries is not easy. I read about the importance of winding clockwise - though never determined if that was part of the issue here. If I always drew polygons clockwise the issue never occured.

    I ended up with my aoi covered in polygons like this (each colour a different named layer/geometry object):

    enter image description here

    Once this was done, manipulating each geometry object in the code editor was relatively straightforward. They can be converted to FeatureCollections and merged (or subtracted) using simple code - see below for my final code.

    It was also then easy to share them between scripts by importing the generated code.

    I hope that helps someone - first attempt at answering a question (even if its my own). :)

    // Convert panel geometries to Feature Collections and merge to create one object.
    var spw = ee.FeatureCollection(stateline_panels_west);
    var spe = ee.FeatureCollection(stateline_panels_east);
    var stateline_panels = spw.merge(spe);
    
    // Convert 'features to mask' geometries to Feature Collections.
    var gc = ee.FeatureCollection(golf_course);
    var sp = ee.FeatureCollection(salt_pan);
    var sc = ee.FeatureCollection(solar_concentrator);
    var h1 = ee.FeatureCollection(hill_1);
    var h2 = ee.FeatureCollection(hill_2);
    var h3 = ee.FeatureCollection(hill_3);
    var mf = ee.FeatureCollection(misc_features);
    
    // Merge geometries to create mask
    var features_to_mask = gc.merge(sp).merge(sc).merge(h1).merge(h2).merge(h3).merge(mf);
    
    // Convert 'Features_to_mask' to geometry (needed to create mask)
    var features_to_mask = features_to_mask.geometry();
    
    // Change name
    var mask = features_to_mask
    
    ///// If site has other solar panels nearby need to add these separately & buffer by 1km
    var extra_mask = ee.Feature(solar_concentrator);
    var extra_mask = extra_mask.buffer(1000);
    var extra_mask = extra_mask.geometry();
    
    ///// Join mask & extra mask into single feature using .union()
    // Geometry objects
    var mask = mask.union(extra_mask);