#include <R.h>
#include <R_ext/Utils.h>
#include "chunkloop.h"

/* 
   linearradius.c

   Bounding radius in linear network

   $Revision: 1.4 $  $Date: 2022/10/23 02:53:55 $

  Copyright (C) Adrian Baddeley, Ege Rubak and Rolf Turner 2001-2018
  Licence: GNU Public Licence >= 2

*/

#define DPATH(I,J) dpath[(J) + Nv * (I)]

#include "yesno.h"

#undef DEBUG

void 
linearradius(
  int *ns,
  int *from,
  int *to,            /* network segments */
  double *lengths,    /* segment lengths */
  int *nv,            /* number of network vertices */
  double *dpath,      /* matrix of shortest path distances between vertices */
  double *huge,       /* very large value */
  double *result 
) {
  int Nv, Ns;
  int i, j, A, B, C, D;
  double AB, AC, AD, BC, BD, CD;
  double sAij, sBij, sAiMax, sBiMax, smin;
  int maxchunk;

  Nv = *nv;
  Ns = *ns;
  smin = *huge;

  OUTERCHUNKLOOP(i, Ns, maxchunk, 16384) {
    R_CheckUserInterrupt();
    INNERCHUNKLOOP(i, Ns, maxchunk, 16384) {
      /* indices of endpoints of segment i */
      A = from[i];
      B = to[i];
      AB = lengths[i];
      sAiMax = sBiMax = AB/2.0;
      for(j = 0; j < Ns; j++) {
	if(j != i) {
	  /* indices of endpoints of segment i */
	  C = from[j];
	  D = to[j];
	  CD = lengths[j];
	  AC = DPATH(A,C);
	  AD = DPATH(A,D);
	  BC = DPATH(B,C);
	  BD = DPATH(B,D);
	  /* max dist from A to any point in segment j */
	  sAij = (AD > AC + CD) ? AC + CD :
 	          (AC > AD + CD) ? AD + CD : (AC + AD + CD)/2.0;
	  /* max dist from B to any point in segment j */
	  sBij = (BD > BC + CD) ? BC + CD : 
  	          (BC > BD + CD) ? BD + CD : (BC + BD + CD)/2.0;
	  /* row-wise maximum */
	  if(sAij > sAiMax) sAiMax = sAij;
	  if(sBij > sBiMax) sBiMax = sBij;
	}
      }
      if(sAiMax < smin) smin = sAiMax;
      if(sBiMax < smin) smin = sBiMax;
    }
  }

  *result = smin;
}

