/**
   * Sets the surface this describes and regenerates all necessary mathematical information. If
   * failure occurs no changes are made.
   *
   * @param f Polynomial in two variables representing the surface
   * @param x First variable in f
   * @param y Second variable in f
   */
  public void setSurface(String f, String x, String y, Point2D basePoint, Point2D sheetsBase)
      throws SetSurfaceException {
    Algebraic newMonodromy;
    HashSet<Point2D> newBranches;
    List newDefiningSheets;

    Point2D newBasePoint = basePoint;
    String s;

    try {
      // First calculate the monodromy

      s = "mono := central_monodromy(Record('f'=%s,'x'=%s, 'y'=%s), %s);";
      s = String.format(s, f, x, y, maple.pointToString(basePoint));
      newMonodromy = maple.evaluate(s);

      List mapBranches = (List) maple.evaluate("map(x->x[1], mono[3]):");
      newBranches = new HashSet<Point2D>();

      for (int i = 1; i <= mapBranches.length(); ++i)
        newBranches.add(maple.algToPoint(mapBranches.select(i)));

      newBasePoint = maple.algToPoint(maple.evaluate("mono[1]:"));
    } catch (MapleException e) {
      throw new SetSurfaceException(
          "Maple's monodromy calculation failed.\n" + "Surface change aborted.\n" + e);
    }

    // Then calculate our canonical sheet numbering at the requested base.
    try {
      List sheets = (List) maple.evaluate("mono[2]:");
      newDefiningSheets =
          maple.propagateSheets(getCurveString(f, x, y), sheets, basePoint, sheetsBase);
    } catch (Exception e) {
      throw new SetSurfaceException(
          "Unable to translate maple's monodromy into unique definition "
              + "of sheets.\n"
              + "Does straight line path from base point to sheets base go too "
              + "close to a branch?\n"
              + e);
    }

    // Do this stuff at end so we can revert before if necessary
    this.f = f;
    this.x = x;
    this.y = y;
    this.sheetsBase = sheetsBase;
    this.branches = newBranches;
    this.monodromy = newMonodromy;
    this.basePoint = newBasePoint;
    this.definingSheets = newDefiningSheets;

    fireSurfaceChangeEvent();
  }
  @Override
  void precalcPermutations() {
    cutsPermutation = new HashMap<Point2D, Algebraic>();

    try {
      maple.assignName("mono", surface.getMonodromy());
      List perms = (List) maple.evaluate("mono[3]:");

      for (int i = 1; i <= perms.length(); ++i) {
        List pair = (List) perms.select(i);
        Point2D branch = maple.algToPoint(pair.select(1));

        cutsPermutation.put(branch, pair.select(2));
      }
    } catch (MapleException e) {
      System.err.println("Unexpected format for monodromy");
      System.err.println(e);
    }
  }