@Override
 public void paint(Graphics2D g2, StateRenderer2D renderer) {
   if (pe != null) {
     Graphics2D g = (Graphics2D) g2.create();
     pe.paint(g, renderer, -renderer.getRotation());
     g.dispose();
   }
 }
  @Override
  public void mouseClicked(MouseEvent event, StateRenderer2D source) {

    if (event.getButton() == MouseEvent.BUTTON3) {
      JPopupMenu popup = new JPopupMenu();
      popup
          .add("Generate plans locally")
          .addActionListener(
              new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                  solve();
                }
              });

      popup
          .add("Clear polygon")
          .addActionListener(
              new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                  pe = null;
                  vertexCount = 0;
                }
              });

      popup
          .add("Settings")
          .addActionListener(
              new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                  PropertiesEditor.editProperties(AreaCoveragePlanner.this, getConsole(), true);
                }
              });

      popup.show(source, event.getX(), event.getY());
    } else if (pe == null) {
      LocationType l = source.getRealWorldLocation(event.getPoint());
      pe =
          new PathElement(
              MapGroup.getMapGroupInstance(getConsole().getMission()), new MapType(), l);
      pe.setMyColor(Color.green.brighter());
      pe.setShape(true);
      pe.setFinished(true);
      pe.setStroke(new BasicStroke(2.0f));
      pe.addPoint(0, 0, 0, false);
      vertexCount = 1;
    } else {
      LocationType l = source.getRealWorldLocation(event.getPoint());
      double[] offsets = l.getOffsetFrom(pe.getCenterLocation());
      pe.addPoint(offsets[1], offsets[0], 0, false);
      vertexCount++;
    }
  }
  private void solve() {

    if (pe == null) {
      GuiUtils.errorMessage(getConsole(), "Coverage Plan Solver", "The polygon is not valid");
      return;
    }

    double north, east, south, west;
    double[] bounds = pe.getBounds3d();

    south = bounds[PathElement.SOUTH_COORD];
    west = bounds[PathElement.WEST_COORD];
    north = bounds[PathElement.NORTH_COORD];
    east = bounds[PathElement.EAST_COORD];

    CoverageCell[][] cells =
        new CoverageCell[(int) ((north - south) / grid) + 1][(int) ((east - west) / grid) + 1];

    for (int i = 0; i < cells.length; i++)
      for (int j = 0; j < cells[i].length; j++) {
        cells[i][j] = new CoverageCell();
        cells[i][j].i = i;
        cells[i][j].j = j;
      }

    int i = 0, j = 0;
    int desiredCells = 0;
    for (double n = south + grid / 2; n < north; n += grid) {
      j = 0;
      for (double e = west + grid / 2; e < east; e += grid) {
        LocationType lt = new LocationType(pe.getCenterLocation());
        lt.translatePosition(n, e, 0);
        CoverageCell cell = cells[i][j];
        cell.realWorldLoc = lt.getNewAbsoluteLatLonDepth();
        if (pe.containsPoint(lt, null)) {
          cell.desired = true;
          desiredCells++;
        }
        cells[i][j] = cell;
        j++;
      }
      i++;
    }

    CoverageCell initialCell = null;
    i = 0;
    for (j = 0; j < cells[0].length - 1 && initialCell == null; j++)
      for (i = 0; i < cells.length && initialCell == null; i++)
        if (cells[i][j].desired) initialCell = cells[i][j];

    if (initialCell == null) {
      GuiUtils.errorMessage("Polygon coverage", "Polygon area is invalid");
      return;
    }

    CoverageCell current = initialCell;
    desiredCells--;

    int dir = -1;

    while (desiredCells > 0) {
      current.visited = true;
      current.active = false;
      if (dir == 1) {
        if (current.i < cells.length - 1
            && cells[current.i + 1][current.j].desired == true
            && cells[current.i + 1][current.j].visited == false) {
          current.next = cells[current.i + 1][current.j];
          cells[current.i + 1][current.j].previous = current;
          current = current.next;
          current.active = true;
        } else {
          dir = -1;
          if (current.j == cells[0].length - 1) break;

          while (!cells[current.i][current.j + 1].desired && i > 0 && current.previous != null) {
            current.active = false;
            current = current.previous;
          }

          if (i == 0) break;

          current.next = cells[current.i][current.j + 1];
          cells[current.i][current.j + 1].previous = current;
          current = current.next;
          current.active = true;
        }
      } else {
        if (current.i > 0
            && cells[current.i - 1][current.j].desired == true
            && cells[current.i - 1][current.j].visited == false) {
          current.next = cells[current.i - 1][current.j];
          cells[current.i - 1][current.j].previous = current;
          current = current.next;
          current.active = true;
        } else {
          dir = 1;
          if (current.j == cells[0].length - 1) break;

          while (current.previous != null
              && !cells[current.i][current.j + 1].desired
              && i < cells.length) {
            current.active = false;
            current = current.previous;
          }

          if (i == cells.length) break;

          current.next = cells[current.i][current.j + 1];
          cells[current.i][current.j + 1].previous = current;
          current = current.next;
          current.active = true;
        }
      }
      desiredCells--;
    }
    generatePlans(cells, initialCell);
  }