cdm/src/main/java/ucar/nc2/dataset/CoordinateAxis2D.java
static public ArrayDouble.D2 makeEdges(ArrayDouble.D2 midpoints) {
    int[] shape = midpoints.getShape();
    int ny = shape[0];
    int nx = shape[1];
    ArrayDouble.D2 edge = new ArrayDouble.D2(ny + 1, nx + 1);

    for (int y = 0; y < ny - 1; y++) {
      for (int x = 0; x < nx - 1; x++) {
        // the interior edges are the average of the 4 surrounding midpoints
        double xval = (midpoints.get(y, x) + midpoints.get(y, x + 1) + midpoints.get(y + 1, x) + midpoints.get(y + 1, x + 1)) / 4;
        edge.set(y + 1, x + 1, xval);
      }
      // extrapolate to exterior points
      edge.set(y + 1, 0, edge.get(y + 1, 1) - (edge.get(y + 1, 2) - edge.get(y + 1, 1)));
      edge.set(y + 1, nx, edge.get(y + 1, nx - 1) + (edge.get(y + 1, nx - 1) - edge.get(y + 1, nx - 2)));
    }

    // extrapolate to the first and last row
    for (int x = 0; x < nx + 1; x++) {
      edge.set(0, x, edge.get(1, x) - (edge.get(2, x) - edge.get(1, x)));
      edge.set(ny, x, edge.get(ny - 1, x) + (edge.get(ny - 1, x) - edge.get(ny - 2, x)));
    }

    return edge;
  }
static public ArrayDouble.D2 makeEdges(ArrayDouble.D2 midpoints) {
    int[] shape = midpoints.getShape();
    int ny = shape[0];
    int nx = shape[1];
    ArrayDouble.D2 edge = new ArrayDouble.D2(ny + 1, nx + 1);

    for (int y = 0; y < ny - 1; y++) {
      for (int x = 0; x < nx - 1; x++) {
        // the interior edges are the average of the 4 surrounding midpoints
        double xval = (midpoints.get(y, x) + midpoints.get(y, x + 1) + midpoints.get(y + 1, x) + midpoints.get(y + 1, x + 1)) / 4;
        edge.set(y + 1, x + 1, xval);
      }
      // extrapolate to exterior points
      edge.set(y + 1, 0, edge.get(y + 1, 1) - (edge.get(y + 1, 2) - edge.get(y + 1, 1)));
      edge.set(y + 1, nx, edge.get(y + 1, nx - 1) + (edge.get(y + 1, nx - 1) - edge.get(y + 1, nx - 2)));
    }

    // extrapolate to the first and last row
    for (int x = 0; x < nx + 1; x++) {
      edge.set(0, x, edge.get(1, x) - (edge.get(2, x) - edge.get(1, x)));
      edge.set(ny, x, edge.get(ny - 1, x) + (edge.get(ny - 1, x) - edge.get(ny - 2, x)));
    }

    return edge;
  }
static public ArrayDouble . D2 makeEdges ( ArrayDouble . D2 midpoints ) { int [ ] shape = midpoints . getShape ( ) ; int ny = shape [ 0 ] ; int nx = shape [ 1 ] ; ArrayDouble . D2 edge = new ArrayDouble . D2 ( ny + 1 , nx + 1 ) ; for ( int y = 0 ; y < ny - 1 ; y ++ ) { for ( int x = 0 ; x < nx - 1 ; x ++ ) { // the interior edges are the average of the 4 surrounding midpoints
 double xval = ( midpoints . get ( y , x ) + midpoints . get ( y , x + 1 ) + midpoints . get ( y + 1 , x ) + midpoints . get ( y + 1 , x + 1 ) ) / 4 ; edge . set ( y + 1 , x + 1 , xval ) ; } // extrapolate to exterior points
 edge . set ( y + 1 , 0 , edge . get ( y + 1 , 1 ) - ( edge . get ( y + 1 , 2 ) - edge . get ( y + 1 , 1 ) ) ) ; edge . set ( y + 1 , nx , edge . get ( y + 1 , nx - 1 ) + ( edge . get ( y + 1 , nx - 1 ) - edge . get ( y + 1 , nx - 2 ) ) ) ; } // extrapolate to the first and last row
 for ( int x = 0 ; x < nx + 1 ; x ++ ) { edge . set ( 0 , x , edge . get ( 1 , x ) - ( edge . get ( 2 , x ) - edge . get ( 1 , x ) ) ) ; edge . set ( ny , x , edge . get ( ny - 1 , x ) + ( edge . get ( ny - 1 , x ) - edge . get ( ny - 2 , x ) ) ) ; } return edge ; }
Normal case: do something reasonable in deciding on the edges when we have the midpoints of a 2D coordinate.

@param midpoints values of midpoints with shape (ny, nx)
@return values of edges with shape (ny+1, nx+1)
Normal case : do something reasonable in deciding on the edges when we have the midpoints of a 2D coordinate .