void
DistanceTransformNonEuclid(vector<double>& D, 
                           const vector<unsigned char>& L, 
                           const vector<int>& leadingNbh,
                           const vector<int>& trailingNbh,
                           const vector<double>& leadingWgt,
                           const vector<double>& trailingWgt,
                           int ndim, 
                           const int* dims) {

  int i,j;
  int nvoxels=numberOfElements(ndim,dims);

  //construct a subscript representation of the neighborhood
  //for efficient boundary check
  vector<int> vcoordsL;
  for(i=0; i<leadingNbh.size(); ++i) {
    vector<int> vsub = Ind2SubCentered(leadingNbh[i],ndim,dims);
    vcoordsL.insert(vcoordsL.end(),vsub.begin(),vsub.end());
  }
  vector<int> vcoordsT;
  for(i=0; i<leadingNbh.size(); ++i) {
    vector<int> vsub = Ind2SubCentered(trailingNbh[i],ndim,dims);
    vcoordsT.insert(vcoordsT.end(),vsub.begin(),vsub.end());
  }

  //first pass - from upper left to lower right
  for(i=0; i<nvoxels; ++i) {
    double v1=GetData(D,i,(double)0);
    double minV=INFINITY;
    vector<int> vsub = Ind2Sub(i,ndim,dims);
    for(j=0; j<leadingNbh.size(); ++j) {
      if(NeighborCheck(vsub.begin(),vcoordsL.begin()+j*ndim,ndim,dims)) {
        int k=i+leadingNbh[j];
        double v2=D[k]; //trust BoundaryCheck - no array boundary check here
        minV=Min(minV,v2+leadingWgt[j]);
      }
    }
    if(v1>minV)
      SetData(D,i,minV);
  }

  //second pass - from lower right to upper left
  for(i=nvoxels-1; i>=0; --i) {
    double v1=GetData(D,i,(double)0);
    double minV=INFINITY;
    vector<int> vsub = Ind2Sub(i,ndim,dims);
    for(j=0; j<trailingNbh.size(); ++j) {
      if(NeighborCheck(vsub.begin(),vcoordsT.begin()+j*ndim,ndim,dims)) {
        int k=i+trailingNbh[j];
        double v2=D[k]; //trust BoundaryCheck - no array boundary check here
        minV=Min(minV,v2+trailingWgt[j]);
     }
    }
    if(v1>minV)
      SetData(D,i,minV);
  }
}
bool
NeighborCheck(int p,
              int offset,
              int ndim, 
              const int* dims) {
  vector<int> vsub = Ind2Sub(p, ndim, dims);
  vector<int> voff = Ind2SubCentered(offset, ndim, dims);
  if(voff.size()>ndim)
    return false; //index overflow

  for(int i=0; i<ndim; ++i) {
    if(vsub[i]+voff[i]<0 || vsub[i]+voff[i]>=dims[i]) {
      return false;
    }
  }
  return true;
}
void
LocalMinimum(vector<unsigned char>& M, 
			 const vector<Item>& V, 
			 const vector<unsigned char>& L,
			 const vector<int>& nbh,
			 bool strict,
			 int ndim,
			 const int* dims) 
{
	int nvoxels = numberOfElements(ndim,dims);
	if(M.size()<nvoxels || V.size()<nvoxels || L.size()<nvoxels) 
	{
		//mexPrintf("An input image does not contain enough data.\n");
		return;
	}

	int i;
	//construct a subscript representation of the neighborhood
	//for efficient boundary check
	vector<int> vcoords;
	for(i=0; i<nbh.size(); ++i) 
	{
		vector<int> vsub = Ind2SubCentered(nbh[i],ndim,dims);
		vcoords.insert(vcoords.end(),vsub.begin(),vsub.end());
	}

	for(i=0; i<nvoxels; ++i) 
	{
		unsigned char lb=L[i];
		if(!lb)
			continue; //not inside ROI
		bool bLM=true;
		bool b0;
		Item origV=V[i];

		vector<int> vsub = Ind2Sub(i,ndim,dims);
		for(int j=0; j<nbh.size(); ++j)
		{
			if(NeighborCheck(vsub.begin(),vcoords.begin()+j*ndim,ndim,dims))
			{ 
				int k=i+nbh[j];
				if(L[k])
				{
					bool b;
					Item v2=V[k];
					if(strict) {// strictly maximum
						if(v2<=origV)
						{
							bLM=false;
							break;
						}
					}
					else 
					{
						if(v2<origV) 
						{
							bLM=false;
							break;
						}
					}
				}
			}
		}

		if(bLM) 
		{
			SetData(M,i,(unsigned char) 1);
		}
		else 
		{
			SetData(M,i,(unsigned char) 0);
		}
	}
}