public Geometry patch(int m, int n, double basisMatrix[][], double data[]) {

      // TO MAKE NORMALS CORRECT AROUND THE EDGES, ALLOCATE EXTRA VERTICES...

      newRectangularMesh(m + 2, n + 2);

      // ...BUT DON'T ATTACH THOSE EXTRA VERTICES TO ANY FACES.

      faces = new int[m * n][4];
      for (int k = 1; k < n + 1; k++)
         for (int j = 1; j < m + 1; j++) {
            int f = (k - 1) * m + j - 1;
            int v = k * (m + 3) + j;
            faces[f][0] = v;
            faces[f][1] = v + 1;
            faces[f][2] = v + m + 3 + 1;
            faces[f][3] = v + m + 3;
         }

      // PUT KNOT DATA INTO PROPER ORDER FOR CONSTRUCTING X,Y,Z BICUBIC SPLINES

      double G[][][] = new double[3][4][4];
      for (int i = 0; i < 4; i++)
         for (int j = 0; j < 4; j++)
            for (int k = 0; k < 3; k++)
               G[k][i][j] = data[12 * i + 3 * j + k];

      // CONSTRUCT THE X,Y,Z COEFFICIENT MATRICES

      Coefs = new double[3][4][4];
      for (int k = 0; k < 3; k++)
         constructBicubicCoefficients(G[k], basisMatrix, Coefs[k]);

      // EVAL X,Y,Z BICUBIC SPLINES TO MAKE POLYGON MESH VERTICES

      int N = 0;
      for (int j = -1; j <= n + 1; j++) {
         double v = (double) j / n;
         for (int i = -1; i <= m + 1; i++) {
            double u = (double) i / m;
            for (int k = 0; k < 3; k++)
               vertices[N][k] = evalBicubic(Coefs[k], u, v);
            N++;
         }
      }

      // FORCE A COMPUTATION OF THE MESH VERTEX NORMALS

      computedMeshNormals = false;
      return this;
   }