void pair_bins_summary::set_log_mag_limits(const flt_type & mag_min,
		const flt_type & mag_max,
		const ssize_t & mag_num_bins)
{
	_set_log_mag_limits(mag_min,mag_max,mag_num_bins);
	_check_limits();
}
void pair_bins_summary::set_log_m_limits(const mass_type & m_min,
		const mass_type & m_max,
		const ssize_t & m_num_bins)
{
	_set_log_m_limits(m_min,m_max,m_num_bins);
	_check_limits();
}
void pair_bins_summary::set_log_z_limits(const flt_type & z_min,
		const flt_type & z_max,
		const ssize_t & z_num_bins)
{
	_set_log_z_limits(z_min,z_max,z_num_bins);
	_check_limits();
}
// Set specific limits through a log spacing
void pair_bins_summary::set_log_R_limits(const distance_type & R_min,
		const distance_type & R_max,
		const ssize_t & R_num_bins)
{
	_set_log_R_limits(R_min,R_max,R_num_bins);
	_check_limits();
}
void pair_bins_summary::set_limits(IceBRG::limit_vector< distance_type > R_bin_limits,
		IceBRG::limit_vector< mass_type > m_bin_limits,
		IceBRG::limit_vector< flt_type > z_bin_limits,
		IceBRG::limit_vector< flt_type > mag_bin_limits)
{
	_set_R_limits(R_bin_limits);
	_set_m_limits(m_bin_limits);
	_set_z_limits(z_bin_limits);
	_set_mag_limits(mag_bin_limits);
	_check_limits();
}
// Set limits by vectors
pair_bins_summary::pair_bins_summary(IceBRG::limit_vector< distance_type > R_bin_limits,
		IceBRG::limit_vector< mass_type > m_bin_limits,
		IceBRG::limit_vector< flt_type > z_bin_limits,
		IceBRG::limit_vector< flt_type > mag_bin_limits)
:	_R_bin_limits_(R_bin_limits),
 	_m_bin_limits_(m_bin_limits),
 	_z_bin_limits_(z_bin_limits),
 	_mag_bin_limits_(mag_bin_limits),
 	_valid_limits_(false)
{
	_check_limits();
}
// Construct from pair_bins
pair_bins_summary::pair_bins_summary( const pair_binner & bins)
:	_R_bin_limits_(bins.R_limits()),
 	_m_bin_limits_(bins.m_limits()),
 	_z_bin_limits_(bins.z_limits()),
 	_mag_bin_limits_(bins.mag_limits()),
 	_valid_limits_(false)
{
	_check_limits();
	if(_valid_limits_)
	{
		bins.sort();
		_pair_bin_summaries_ = bins.pair_bin_summaries();
	}
}
void pair_bins_summary::set_log_limits(const distance_type & R_min,
			const distance_type & R_max,
			const ssize_t & R_num_bins,
			const mass_type & m_min,
			const mass_type & m_max,
			const ssize_t & m_num_bins,
			const flt_type & z_min,
			const flt_type & z_max,
			const ssize_t & z_num_bins,
			const flt_type & mag_min,
			const flt_type & mag_max,
			const ssize_t & mag_num_bins)
{
	_set_log_R_limits(R_min,R_max,R_num_bins);
	_set_log_m_limits(m_min,m_max,m_num_bins);
	_set_log_z_limits(z_min,z_max,z_num_bins);
	_set_log_mag_limits(mag_min,mag_max,mag_num_bins);
	_check_limits();
}
// Set limits by min, max, and step
pair_bins_summary::pair_bins_summary(const distance_type & R_min,
				const distance_type & R_max,
				const ssize_t & R_bins,
				const mass_type & m_min,
				const mass_type & m_max,
				const ssize_t & m_bins,
				const flt_type & z_min,
				const flt_type & z_max,
				const ssize_t & z_bins,
				const flt_type & mag_min,
				const flt_type & mag_max,
				const ssize_t & mag_bins)
:	_R_bin_limits_(IceBRG::limit_vector<distance_type>::type::LINEAR,R_min,R_max,R_bins),
 	_m_bin_limits_(IceBRG::limit_vector<mass_type>::type::LINEAR,m_min,m_max,m_bins),
 	_z_bin_limits_(IceBRG::limit_vector<flt_type>::type::LINEAR,z_min,z_max,z_bins),
 	_mag_bin_limits_(IceBRG::limit_vector<flt_type>::type::LINEAR,mag_min,mag_max,mag_bins),
 	_valid_limits_(false)
{
	_check_limits();
}
/**
 * lw6ldr_resampler_init
 *
 * @sys_context: global system context
 * @resampler: resampler object to init
 * @param: map parameters to use
 * @hints: loading hints
 * @source_w: width of source map
 * @source_h: height of source map
 * @display_w: width of source display
 * @display_h: height of source display
 * @target_ratio: ratio, that is width/height of the target
 * @bench_value: rough estimation of this computer power
 * @magic_number: arbitrary constant, needed to calibrate speed
 * @expected_depth: how thick the map could be (in practice, looks like d in whd)
 * @gray_level: used to estimate capacity, 1.0f is white and means many slots
 *
 * Initializes a resampler. There is wizardry based on the bench, magic number
 * map size, gray level. This is bot bullet proof, but has been experience
 * driven and is the result of many tries / failures and hopefully successes.
 * Might need tuning as the algorithm evolves. This is the very function that
 * chooses the actual logical map size.
 *
 * Return value: none.
 */
void
lw6ldr_resampler_init (lw6sys_context_t * sys_context, lw6ldr_resampler_t * resampler,
		       lw6map_param_t * param, const lw6ldr_hints_t * hints,
		       int source_w,
		       int source_h, int display_w, int display_h, float target_ratio, int bench_value, int magic_number, int expected_depth, float gray_level)
{
  int target_w = 0;
  int target_h = 0;
  int tmp_w = 0;
  int tmp_h = 0;
  float f;
  float fighter_scale;
  float required;
  float capacity;
  float capacity_orig;
  int lin_bench_value;

  memset (resampler, 0, sizeof (lw6ldr_resampler_t));

  target_w = source_w;
  target_h = source_h;

  if (source_w > 0 && source_h > 0)
    {
      if (hints->resample)
	{
	  _check_limits (sys_context, hints, &target_w, &target_h);

	  /*
	   * Step 1, we use fighter scale to get our target size
	   * This also includes zoom.
	   */
	  // 0*0=0 so size must be non-zero
	  if (hints->fighter_scale > 0.0f)
	    {
	      fighter_scale = hints->fighter_scale;
	    }
	  else
	    {
	      fighter_scale = LW6LDR_HINTS_DEFAULT_FIGHTER_SCALE;
	    }
	  tmp_w = display_w * param->style.zoom / fighter_scale;
	  tmp_h = display_h * param->style.zoom / fighter_scale;
	  if (hints->downsize_using_fighter_scale && tmp_w * tmp_h < target_w * target_h)
	    {
	      target_w = tmp_w;
	      target_h = tmp_h;
	      lw6sys_log (sys_context, LW6SYS_LOG_INFO,
			  _x_
			  ("fighter_scale=%f on display %dx%d -> downsizing from %dx%d to %dx%d"),
			  hints->fighter_scale, display_w, display_h, source_w, source_h, target_w, target_h);
	    }
	  else if (hints->upsize_using_fighter_scale && tmp_w * tmp_h > target_w * target_h)
	    {
	      target_w = tmp_w;
	      target_h = tmp_h;
	      lw6sys_log (sys_context, LW6SYS_LOG_INFO,
			  _x_
			  ("fighter_scale=%f on display %dx%d -> upsizing from %dx%d to %dx%d"),
			  hints->fighter_scale, display_w, display_h, source_w, source_h, target_w, target_h);
	    }

	  _check_limits (sys_context, hints, &target_w, &target_h);

	  /*
	   * Step 2, we correct the ratio
	   */
	  if (target_w > 0 && target_h > 0)
	    {
	      f = target_ratio / (((float) target_w) / ((float) target_h));
	      if (f > 1.0f)
		{
		  target_w *= f;
		}
	      else if (f < 1.0f)
		{
		  target_h /= f;
		}
	    }

	  _check_limits (sys_context, hints, &target_w, &target_h);

	  /*
	   * Step 3, take bench in account
	   */
	  lin_bench_value = lw6sys_math_log2lin (sys_context, bench_value, LW6MAP_LOG2LIN_BASE);
	  capacity_orig = ((float) lin_bench_value) * ((float) magic_number);
	  capacity = capacity_orig;
	  required = _estimate_capacity (sys_context, &param->rules, hints, target_w, target_h, expected_depth, gray_level);
	  if (required > 0.0f)
	    {
	      f = 1.0f;
	      if (hints->downsize_using_bench_value && capacity < required)
		{
		  while (capacity < required && tmp_w > LW6MAP_MIN_BODY_WIDTH && tmp_h > LW6MAP_MIN_BODY_HEIGHT)
		    {
		      f *= _RESAMPLER_DOWNSIZE;
		      tmp_w = target_w * f;
		      tmp_h = target_h * f;
		      required = _estimate_capacity (sys_context, &param->rules, hints, tmp_w, tmp_h, expected_depth, gray_level);
		    }
		  if (tmp_w != target_w || tmp_h != target_h)
		    {
		      lw6sys_log (sys_context, LW6SYS_LOG_INFO,
				  _x_
				  ("required=%f capacity=%f bench_value=%d lin_bench_value=%d -> downsizing from %dx%d to %dx%d"),
				  required, capacity_orig, bench_value, lin_bench_value, target_w, target_h, tmp_w, tmp_h);
		      target_w = tmp_w;
		      target_h = tmp_h;
		    }
		}
	      else if (hints->upsize_using_bench_value && capacity > required)
		{
		  while (capacity < required && tmp_w < LW6MAP_MAX_BODY_WIDTH && tmp_h < LW6MAP_MAX_BODY_HEIGHT)
		    {
		      f *= _RESAMPLER_UPSIZE;
		      tmp_w = target_w * f;
		      tmp_h = target_h * f;
		      required = _estimate_capacity (sys_context, &param->rules, hints, tmp_w, tmp_h, expected_depth, gray_level);
		    }
		  if (tmp_w != target_w || tmp_h != target_h)
		    {
		      lw6sys_log (sys_context, LW6SYS_LOG_INFO,
				  _x_
				  ("required=%f capacity=%f bench_value=%d -> upsizing from %dx%d to %dx%d"),
				  required, capacity_orig, bench_value, target_w, target_h, tmp_w, tmp_h);
		      target_w = tmp_w;
		      target_h = tmp_h;
		    }
		}
	    }

	  _check_limits (sys_context, hints, &target_w, &target_h);

	  /*
	   * Step 4, guess speed if needed
	   */
	  _guess_moves_per_sec (sys_context, &param->rules, hints, target_w, target_h);

	  /*
	   * Step 4, we check against map surface limits
	   */
	  if (target_w * target_h > hints->max_map_surface)
	    {
	      lw6sys_log (sys_context, LW6SYS_LOG_DEBUG,
			  _x_ ("target_w=%d target_h=%d hints->max_map_surface=%d -> downsizing"), target_w, target_h, hints->max_map_surface);
	      f = sqrt ((((float) target_w) * ((float) target_h)) / ((float) hints->max_map_surface));
	      target_w /= f;
	      target_h /= f;
	    }

	  if (target_w * target_h < hints->min_map_surface)
	    {
	      lw6sys_log (sys_context, LW6SYS_LOG_DEBUG,
			  _x_ ("target_w=%d target_h=%d hints->min_map_surface=%d -> upsizing"), target_w, target_h, hints->min_map_surface);
	      f = sqrt (((float) hints->min_map_surface) / (((float) target_w) * ((float) target_h)));
	      target_w *= f;
	      target_h *= f;
	    }

	  _check_limits (sys_context, hints, &target_w, &target_h);
	}
    }
  else
    {
      lw6sys_log (sys_context, LW6SYS_LOG_WARNING, _x_ ("unable to handle map with shape %dx%d"), source_w, source_h);
    }

  resampler->target_w = target_w;
  resampler->target_h = target_h;
  resampler->source_w = source_w;
  resampler->source_h = source_h;
  resampler->scale_x = ((float) (resampler->target_w)) / ((float) (resampler->source_w));
  resampler->scale_y = ((float) (resampler->target_h)) / ((float) (resampler->source_h));
}
void pair_bins_summary::clear_mag_limits()
{
	_clear_mag_limits();
	_check_limits();
}
void pair_bins_summary::set_mag_limits(IceBRG::limit_vector< flt_type > mag_bin_limits)
{
	_set_mag_limits(mag_bin_limits);
	_check_limits();
}
void pair_bins_summary::set_m_limits(IceBRG::limit_vector< mass_type > m_bin_limits)
{
	_set_m_limits(m_bin_limits);
	_check_limits();
}
// Set specific limits through a limits vector
void pair_bins_summary::set_R_limits(IceBRG::limit_vector< distance_type > R_bin_limits)
{
	_set_R_limits(R_bin_limits);
	_check_limits();
}