Exemplo n.º 1
0
  public static int computeMaximumOnCircle(double[] a, double[] normal) {
    double db0, db1, db2, db3, db4;
    double val1;
    double[] zeros = new double[4];
    double u, v, maxval, maxu = -1, maxv = -1, inc, arg, polyval;
    int index, nroots;

    index = -1;
    nroots = -1;

    db0 = a[2] - a[3];
    db1 = 4 * a[1] - 2 * a[4] - 4 * a[0];
    db2 = -6 * a[2];
    db3 = -4 * a[1] - 2 * a[4] + 4 * a[0];
    db4 = a[2] + a[3];

    /** polynomial is constant on circle, pick (0,1) as a solution */
    if (Math.abs(db0) < zerotol
        && Math.abs(db1) < zerotol
        && Math.abs(db2) < zerotol
        && Math.abs(db3) < zerotol) {
      normal[0] = 0.0;
      normal[1] = 1.0;
      return 1;
    }

    if (db0 != 0) {
      double[] c = new double[] {db4, db3, db2, db1, db0};
      nroots = GraphicsGems.SolveQuartic(c, zeros);
    } else if (db1 != 0) {
      double[] c = new double[] {db4, db3, db2, db1};
      nroots = GraphicsGems.SolveCubic(c, zeros);
    } else
    /** TODO case where db2 is zero */
    {
      double[] c = new double[] {db4, db3, db2};
      nroots = GraphicsGems.SolveQuadric(c, zeros);
    }
    if (nroots <= 0) {
      return -1;
    }

    switch (nroots) {
      case 1:
        index = 0;
        break;
      default:
        double[] vals = new double[nroots];
        for (int i = 0; i < vals.length; i++) {
          vals[i] = evalPoly(a, zeros[i]);
        }
        index = Utils.indexOfMax(vals);
    }

    /**
     * I noticed that the fact that the pont (0,-1) on the circle can only be attained in the limit
     * causes it to be missed in case it really is the maximum. Hence it is necessary to investigate
     * a neighboring region to find the potential maximum there, we look at the segment from 260
     * degress to 280 degrees (270 degrees being the limit point).
     */
    normal[0] = 2 * zeros[index] / (1 + zeros[index] * zeros[index]);
    normal[1] = (1 - zeros[index] * zeros[index]) / (1 + zeros[index] * zeros[index]);

    /** test the correctness of solution: */
    maxval = -1000;

    for (int k = 0; k <= 20; k++) {
      inc = (1 / 9.0) / 20 * k;
      arg = Math.PI * (26.0 / 18.0 + inc);
      u = Math.cos(arg);
      v = Math.sin(arg);
      polyval = a[0] * u * u + a[1] * v * v + a[2] * u * v + a[3] * u + a[4] * v + a[5];
      if (maxval < polyval) {
        maxval = polyval;
        maxu = u;
        maxv = v;
      }
    }

    val1 = evalPoly(a, zeros[index]);
    if (maxval > val1) {
      normal[0] = maxu;
      normal[1] = maxv;
    }
    return 1;
  }
Exemplo n.º 2
0
  public static Vec3f[] getNormals(int[][] coeff) {

    Vec3f[] normals = new Vec3f[coeff.length];
    double[] a;
    double length2d;
    double disc;
    int stat;
    int maxfound;

    for (int i = 0; i < normals.length; i++) {
      double[] normal = new double[3];
      a = new double[6];
      a[0] = (double) coeff[i][0];
      a[1] = (double) coeff[i][1];
      a[2] = (double) coeff[i][2];
      a[3] = (double) coeff[i][3];
      a[4] = (double) coeff[i][4];
      a[5] = (double) coeff[i][5];

      /* now remove factor of 256 in scaling values */
      a[0] /= 256;
      a[1] /= 256;
      a[2] /= 256;
      a[3] /= 256;
      a[4] /= 256;
      a[5] /= 256;

      /*
       * These coordinates are where the first deriviative of the
       * polynominal is zero
       */
      /* Derivation in lab notebook 2951-43 */
      /*
       * normal[0] = (2 * a[1] * a[3] - (a[4] / a[2]) ) / (1.0 - 4 * a[0] *
       * a[1]);
       */

      /** zero denominator in upcoming computations */
      if (Math.abs(a[2] * a[2] - 4 * a[1] * a[0]) < zerotol) {
        normal[0] = 0;
        normal[1] = 0;
      } else {
        if (Math.abs(a[2]) < zerotol) {
          normal[0] = -1.0 * a[3] / (2.0 * a[0]);
          normal[1] = -1.0 * a[4] / (2.0 * a[1]);
        } else {
          normal[0] = (2.0 * a[1] * a[3] - a[2] * a[4]) / (a[2] * a[2] - 4.0 * a[1] * a[0]);
          normal[1] = (-2.0 * a[0] * normal[0] - a[3]) / a[2];
        }
      }

      /** polynomial is constant we are done, set normal to be at 0,0,1 */
      if (Math.abs(a[0]) < zerotol
          && Math.abs(a[1]) < zerotol
          && Math.abs(a[2]) < zerotol
          && Math.abs(a[3]) < zerotol
          && Math.abs(a[4]) < zerotol) {
        normal[0] = 0.0;
        normal[1] = 0.0;
        normal[2] = 1.0;
      }
      /**
       * clip normal[0], normal[1] values - these can both be unbounded theoretically. first check
       * if the vector (normal[0],normal[1]) is greater than 1
       */
      else {
        length2d = normal[0] * normal[0] + normal[1] * normal[0];

        /*
         * Add check for saddle or minimum. if p_uu >0 and/or
         * p_uu*p_vv-p_uv*p_uv <0 -> saddle or minimum if this is the
         * case then we should always look at boundary
         */
        if (4 * a[0] * a[1] - a[2] * a[2] > eps && a[0] < -eps) maxfound = 1;
        else maxfound = 0;

        /**
         * Changed by Hans J. Wolters 12-11-99: instead of clipping, we attempt to find the minimum
         * value on the circle. we know that since the polynomial is monotonous in the interior the
         * extrema must be attained at the boundary. The circle will be parametrized by x =
         * 2t/(1+t^2), y = (1-t^2)/(1+t^2). by using Maple we derived the polynomial in t and
         * subsequently its derivative wrt t, a quartic. The task is to find the real root(s) of
         * this polynomial. We denote the 3 coefficients as db0,db1,db2,db3, db4 For precise
         * derivation see Hans Wolters' lab book
         */
        if (length2d > 1 - eps || maxfound == 0) {
          stat = computeMaximumOnCircle(a, normal);
          if (stat == -1) // failed
          {
            length2d = Math.sqrt(length2d);
            if (length2d > zerotol) {
              normal[0] /= length2d;
              normal[1] /= length2d;
            }
          }
        }
        disc = 1.0 - normal[0] * normal[0] - normal[1] * normal[1];
        if (disc < 0.0) {
          normal[2] = 0;
        } else {
          normal[2] = (float) Math.sqrt(disc);
        }
      }
      normal = Utils.normalize3(normal);
      normals[i] = new Vec3f((float) normal[0], (float) normal[1], (float) normal[2]);
    }
    return normals;
  }