class PolygonTurningSimilarity {

  private Result h_t0min(TurnRep f, TurnRep g, double hc0_init, double slope_init,
                         double alpha, int d_update) {
    int left_to_update; /* # disconts left until update */
    double metric2, min_metric2; /* d^2 and d^2_min thus far */
    double theta_star, min_theta_star; /* theta* and theta*_min thus far */
    double last_t; /* t of last iteration */
    double hc0_err, slope_err; /* error mags discovered on update */
    double hc0 = hc0_init;
    double slope = slope_init;
    Event e; /* current event */
    Event min_e; /* event of d^2_min thus far */
    /*
     * At t = 0, theta_star is just alpha, and the min metric2 seen so far is
     * hc0 - min_theta_star^2. Also, no error has been seen.
     */
    min_theta_star = alpha;
    min_metric2 = hc0 - min_theta_star * min_theta_star;
    min_e = new Event(0.0, 0, 0);/* implicit first event */
    last_t = hc0_err = slope_err = 0.0d;
    /*
     * Compute successive hc_i0's by incremental update at critical events as
     * described in the paper.
     */
    left_to_update = d_update;
    while (!this.event.isEmpty()) {
      e = next_event();
      hc0 += (e.t - last_t) * slope;
      theta_star = alpha - 2 * Math.PI * e.t;
      metric2 = hc0 - theta_star * theta_star;
      if (metric2 < min_metric2) {
        min_metric2 = metric2;
        min_theta_star = theta_star;
        min_e = e;
      }
      /*
       * Update slope, last t, and put next event for this g discontinuity in
       * the heap.
       */
      slope += 2 * (f.theta(e.fi - 1) - f.theta(e.fi))
          * (g.theta(e.gi - 1) - g.theta(e.gi));
      last_t = e.t;
      add_event(f, g, e.fi + 1, e.gi);
      /*
       * Re-establish hc0 and slope now and then to reduce numerical error. If
       * d_update is 0, do nothing. Note we don't update if an event is close,
       * as this causes numerical ambiguity. The test number could be much
       * smaller, but why tempt Murphey? We force an update on last event so
       * there's always at least one.
       */
      if (d_update != 0
          && (this.event.isEmpty() || --left_to_update <= 0
              && e.t - last_t > 0.001 && next_t() - e.t > 0.001)) {
        InitVals newVals = reinit_vals(f, g, e.fi, e.gi);
        double rihc0 = newVals.ht0;
        double rislope = newVals.slope;
        double dhc0 = hc0 - rihc0;
        double dslope = slope - rislope;
        if (Math.abs(dhc0) > Math.abs(hc0_err))
          hc0_err = dhc0;
        if (Math.abs(dslope) > Math.abs(slope_err))
          slope_err = dslope;
        hc0 = rihc0;
        slope = rislope;
        left_to_update = d_update;
      }
    }
    /*
     * Set up return values.
     */
    return new Result(min_metric2, min_theta_star, min_e, hc0_err, slope_err);
  }

}