code: private static Geometry shadowPolygon(Polygon polygon, double[] shadowOffset, GeometryFactory factory, boolean doUnion) {
          Coordinate[] shellCoords = polygon.getExteriorRing().getCoordinates();
          Collection<Polygon> shadows = new ArrayList<Polygon>();
          createShadowPolygons(shadows, shellCoords, shadowOffset, factory);
          final int nbOfHoles = polygon.getNumInteriorRing();
          for (int i = 0; i < nbOfHoles; i++) {
              createShadowPolygons(shadows, polygon.getInteriorRingN(i).getCoordinates(), shadowOffset, factory);
          }
          if (!doUnion) {
              return factory.buildGeometry(shadows);
          } else {
              if (!shadows.isEmpty()) {
                  Collection<Geometry> shadowParts = new ArrayList<Geometry>();
                  for (Polygon shadowPolygon : shadows) {
                      shadowParts.add(shadowPolygon.difference(polygon));
                  }
                  Geometry allShadowParts = factory.buildGeometry(shadowParts);
                  Geometry union = allShadowParts.buffer(0);
                  union.apply(new UpdateZCoordinateSequenceFilter(0, 1));
                  return union;
              }
              return null;
          }
          
      }
docs: Compute the shadow for a polygon
  
  @param polygon the input polygon
  @param shadowOffset computed according the sun position and the height of
  the geometry
  @return