Пример #1
0
  /**
   * Returns the total area of this winding.
   *
   * @return total area
   */
  public float getArea() {
    float total = 0;
    final int size = verts.size();

    for (int i = 2; i < size; i++) {
      Vector3f v1 = verts.get(i - 1).sub(verts.get(0));
      Vector3f v2 = verts.get(i).sub(verts.get(0));
      total += v1.cross(v2).length();
    }

    return total * 0.5f;
  }
Пример #2
0
  /**
   * Compare two windings, taking into account that start points may not match
   *
   * @param that other winding
   * @return true if it matches this winding
   */
  public boolean matches(Winding that) {
    final int size = verts.size();

    // if windings have different number of points, trivially fail
    if (size != that.verts.size()) {
      return false;
    }

    // minimum match distance
    float min = 1e6f;

    for (int i = 0; i < size; i++) {
      float mdist = 0;

      // get the aggregate distance at offset i
      for (int j = 0; j < size; j++) {
        // wrap index if greater than size
        int k = (j + i) % size;

        // distance between vertex j of this and k of that
        mdist += verts.get(j).sub(that.verts.get(k)).length();
      }

      // update minimum match distance
      min = Math.min(min, mdist);
    }

    // check if match was close enough
    return min < EPS_COMP;
  }
Пример #3
0
  public Winding addBackface() {
    if (verts.isEmpty()) {
      return this;
    }

    List<Vector3f> vertsNew = new ArrayList<>();

    final int size = verts.size();

    for (int i = 0; i < size; i++) {
      if (i != 0) {
        vertsNew.add(verts.get(i));
      }
      if (i != size) {
        vertsNew.add(verts.get(i));
      }
    }

    return new Winding(vertsNew);
  }
Пример #4
0
  /**
   * Removes collinear vertices from this winding.
   *
   * @return number of removed vertices
   */
  public Winding removeCollinear() {
    if (verts.isEmpty()) {
      return this;
    }

    ArrayList<Vector3f> vertsNew = new ArrayList<>();

    final int size = verts.size();

    for (int i = 0; i < size; i++) {
      int j = (i + 1) % size;
      int k = (i + size - 1) % size;
      Vector3f v1 = verts.get(j).sub(verts.get(i)).normalize();
      Vector3f v2 = verts.get(i).sub(verts.get(k)).normalize();

      if (v1.dot(v2) < 0.999) {
        vertsNew.add(verts.get(i));
      }
    }

    return new Winding(vertsNew);
  }
Пример #5
0
  /**
   * Checks if this winding contains any duplicate vertices.
   *
   * @return true if this winding contains duplicate vertices
   */
  public boolean hasDuplicates() {
    final int size = verts.size();

    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        if (i == j) {
          continue;
        }

        Vector3f v1 = verts.get(i);
        Vector3f v2 = verts.get(j);

        if (v1.equals(v2)) {
          return true;
        }
      }
    }

    return false;
  }
Пример #6
0
  /**
   * Removes degenerated vertices from this winding. A vertex is degenerated when its distance to
   * the previous vertex is smaller than {@link EPS_DEGEN}.
   *
   * @return number of removed vertices
   */
  public Winding removeDegenerated() {
    if (verts.isEmpty()) {
      return this;
    }

    ArrayList<Vector3f> vertsNew = new ArrayList<>();

    final int size = verts.size();

    for (int i = 0; i < size; i++) {
      int j = (i + 1) % size;
      Vector3f v1 = verts.get(i);
      Vector3f v2 = verts.get(j);

      if (v1.sub(v2).length() > EPS_DEGEN) {
        vertsNew.add(v1);
      }
    }

    return new Winding(vertsNew);
  }
Пример #7
0
  /**
   * Clips this winding to a plane defined by a normal and distance, removing all vertices in front
   * or behind it.
   *
   * <p>Equals ClipWindingEpsilon() in polylib.cpp
   *
   * @param normal plane normal
   * @param dist plane distance to origin
   * @param eps clipping epsilon
   * @param back keep vertices behind the plane?
   */
  public Winding clipEpsilon(Vector3f normal, float dist, float eps, boolean back) {
    // counts number of front, back and on vertices
    int[] counts = new int[] {0, 0, 0};
    final int size = verts.size();
    float[] dists = new float[size + 1];
    int[] sides = new int[size + 1];

    // determine sides for each point
    for (int i = 0; i < size; i++) {
      // distance along norm-dirn from origin to vertex
      float dot = verts.get(i).dot(normal);

      // distance along norm-dirn from clip plane to vertex
      dot -= dist;

      // store it
      dists[i] = dot;

      if (dot > eps) {
        // vertex in front of plane
        sides[i] = SIDE_FRONT;
      } else if (dot < -eps) {
        // vertex behind plane
        sides[i] = SIDE_BACK;
      } else {
        // vertex on plane (within epsilon)
        sides[i] = SIDE_ON;
      }

      // count relative vertex positions
      counts[sides[i]]++;
    }

    sides[size] = sides[0]; // loop around to 0'th
    dists[size] = dists[0];

    if (counts[SIDE_FRONT] == 0) {
      // no vertices in front - all behind clip plane
      if (!back) {
        return EMPTY;
      } else {
        return this;
      }
    }
    if (counts[SIDE_BACK] == 0) {
      // no vertices in back - all in front of clip plane
      if (back) {
        return EMPTY;
      } else {
        return this;
      }
    }

    List<Vector3f> vertsNew = new ArrayList<Vector3f>();

    for (int i = 0; i < size; i++) {
      // get i'th vertex
      Vector3f p1 = verts.get(i);

      if (sides[i] == SIDE_ON) {
        vertsNew.add(p1);
        continue;
      }

      if (sides[i] == SIDE_FRONT && !back) {
        // add copy the current vertex
        vertsNew.add(p1);
      }

      if (sides[i] == SIDE_BACK && back) {
        // add copy the current vertex
        vertsNew.add(p1);
      }

      if (sides[i + 1] == SIDE_ON) {
        // next vertex is on the plane, so go to next vertex stat
        continue;
      }

      if (sides[i + 1] == sides[i]) {
        // next vertex does not change side, so go to next vertex stat
        continue;
      }

      // otherwise, we are crossing the clip plane between this vertex and the next
      // so generate a split point

      // will contain the next vertex position
      Vector3f p2;

      if (i == size - 1) {
        // we're the last vertex in the winding
        // next vertex is the 0'th one
        p2 = verts.get(0);
      } else {
        // else get the next vertex
        p2 = verts.get(i + 1);
      }

      // dot is fractional position of clip plane between
      // this vertex and the next
      float dot = dists[i] / (dists[i] - dists[i + 1]);

      // vector of the split vertex
      Vector3f mv = Vector3f.NULL;

      for (int j = 0; j < normal.size; j++) {
        // avoid round off error when possible
        if (normal.get(j) == 1) {
          mv = mv.set(j, dist);
        } else if (normal.get(j) == -1) {
          mv = mv.set(j, -dist);
        } else {
          // check it! MSH
          mv = mv.set(j, p1.get(j) + dot * (p2.get(j) - p1.get(j)));
        }
      }

      // write the output vertex
      vertsNew.add(mv);
    }

    return new Winding(vertsNew);
  }
Пример #8
0
 @Override
 public Vector3f get(int index) {
   return verts.get(index);
 }