Android Open Source - Schooner-3D Face






From Project

Back to project page Schooner-3D.

License

The source code is released under:

Apache License

If you think the Android project Schooner-3D listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2012 Dan Mercer//  www  .j a v a  2s.  com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.supermercerbros.gameengine.collision;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.ListIterator;

public class Face extends Plane implements Feature {

  /**
   * A List of the Edges in that border this face
   */
  private final ArrayList<Edge> edges;
  /**
   * A List of the constraint planes that make up this Face's voronoi region.
   * 
   * Constraint planes <b>always</b> face away from edges, toward faces and
   * vertices.
   */
  private final ArrayList<Plane> voronoi;
  /**
   * The number of edges in this face. Equal to edges.size()
   */
  private final int edgeCount;
  
  // Fields for debugging:
  private final String debugID;
  private static int nextID = 0;

  @Override
  public String toString() {
    return debugID;
  }

  public ArrayList<Edge> getEdges() {
    return edges;
  }

  public Face(Vector normal, Edge... edges) {
    super(getAveragePoint(edges), normal);
    if (edges.length < 3) {
      throw new IllegalArgumentException(
          "A Face cannot be constructed with less than 3 edges.");
    }
    this.edges = new ArrayList<Edge>(Arrays.asList(edges));
    this.voronoi = new ArrayList<Plane>();

    for (final Edge edge : edges) {
      final Plane constraint = edge.addFace(this, point);
      voronoi.add(constraint);
    }

    edgeCount = this.edges.size();

    this.debugID = "Face " + nextID++;
  }

  private static Point getAveragePoint(Edge[] edges) {
    float avgX = 0, avgY = 0, avgZ = 0;
    for (final Edge edge : edges) {
      avgX += edge.head.x;
      avgY += edge.head.y;
      avgZ += edge.head.z;
    }
    avgX /= edges.length;
    avgY /= edges.length;
    avgZ /= edges.length;

    return new Point(avgX, avgY, avgZ);
  }

  public static void resetIdCounter() {
    nextID = 0;
  }

  @Override
  public Feature test(Feature other, Matrix matrix) throws Intersection,
      LocalDistMinimum {
    if (other instanceof Face) {
      return testF((Face) other, matrix);
    } else if (other instanceof Edge) {
      return testE((Edge) other, matrix);
    } else if (other instanceof Vertex) {
      return testV((Vertex) other, matrix);
    } else {
      throw new IllegalArgumentException(
          "other is not a Face, Edge, or Vertex");
    }
  }

  private Feature testF(Face face, Matrix matrix) throws LocalDistMinimum {
    final Plane tFace = face.transform(matrix);

    final boolean parallel = Math.abs(tFace.normal.dot(this.normal)) == 1.f;
    if (parallel) { // Faces are parallel; check if they overlap when
            // projected together.
      Point potentialClosest = tFace.projectPointOnto(Point.average(
          tFace.point, this.point));
      double distance = CollisionDetector.CONSTRAINT_CHECK_TOLERANCE;
      Edge infringed = null;

      for (ListIterator<Plane> vIter = voronoi.listIterator(); vIter
          .hasNext();) {
        final int i = vIter.nextIndex();
        final Plane constraint = vIter.next();

        final double d = constraint.distanceTo(potentialClosest);
        if (d < distance) {
          distance = d;
          infringed = edges.get(i);
        }
      }

      if (infringed == null
          && this.distanceTo(potentialClosest) < CollisionDetector.CONSTRAINT_CHECK_TOLERANCE) {
        throw new LocalDistMinimum(potentialClosest);
      }
      if (infringed != null) {
        for (final Edge edge : face.edges) {
          final Point p = edge.head.transform(matrix);
          if (pointPasses(p)) {
            CollisionDetector
                .setDistance(distanceTo(potentialClosest));
            return null;
          }
        }
        return infringed;
      } else {
        CollisionDetector.setClosestPoint(potentialClosest);
        return null;
      }
    } else { // Not parallel, not closest.
      Vertex v1 = edges.get(0).head;
      double distance = Math.abs(tFace.distanceTo(v1));
      Vertex closer = v1;

      for (int i = 1; i < edgeCount; i++) {
        final Vertex v = edges.get(i).head;
        final double d = Math.abs(tFace.distanceTo(v));
        if (d < distance) {
          distance = d;
          closer = v;
        }
      }

      return closer;
    }
  }

  /**
   * Checks the Point p (given in this Face's coordinate system) against this
   * Face's voronoi region.
   * 
   * @param p
   *            The point to check.
   * @return
   */
  public boolean pointPasses(Point p) {
    for (final Plane constraint : voronoi) {
      final double d = constraint.distanceTo(p);
      if (d < CollisionDetector.CONSTRAINT_CHECK_TOLERANCE) {
        return false;
      }
    }
    return true;
  }

  /**
   * Checks the Point p (given in global coordinates) against this Face's
   * voronoi region.
   * 
   * @param p
   *            The point to check.
   * @param faceM
   *            The matrix defining this Face's transformation.
   * @return
   */
  public boolean pointPasses(Point p, Matrix faceM) {
    for (final Plane constraint : voronoi) {
      final double d = constraint.transform(faceM).distanceTo(p);
      if (d < CollisionDetector.CONSTRAINT_CHECK_TOLERANCE) {
        return false;
      }
    }
    return true;
  }

  private Edge testE(Edge edge, Matrix matrix) throws Intersection,
      LocalDistMinimum {
    final Line tEdge = edge.transform(matrix);
    final Vector tVector = tEdge.vector;
    final Point intersection = intersect(tEdge);
    final Point head = tEdge.head, tail = tEdge.tail;

    if (intersection != null) {
      // If edge intersects plane

      int index = -1;
      double distance = 0.0;
      for (int i = 0; i < edgeCount; i++) {
        Plane constraint = voronoi.get(i);

        double d = constraint.distanceTo(intersection);

        if (d < distance) {
          distance = d;
          index = i;
        }

      }
      if (index > -1) {
        return edges.get(index);
      } else {
        throw new Intersection(intersection);
      }

    } else if (tVector.cos(normal) == 0.0) {
      // If edge is parallel to Face

      Point headward = null, tailward = null;
      float hDistance = tEdge.length;
      float tDistance = hDistance;
      float twh = 0.0f;
      int index = -1;

      for (int i = 0; i < edgeCount; i++) {
        final Plane constraint = voronoi.get(i);

        // For each constrant plane, intersect it with edge.
        final Point p = constraint.intersect(tEdge);

        if (p == null) {
          // If the edge does not intersect the constraint

          if (constraint.pointIsInFront(head)) {
            // If the edge is in front of the constraint
            continue;
          } else {
            // If the edge is behind the constraint, we know
            // it is not the closest feature
            if (index == -1) {
              hDistance = 0.0f;
            }
            index = i;
            double d = constraint.distanceTo(head);
            if (d < hDistance) {
              hDistance = (float) d;
            }
          }

        } else {
          // If the edge does intersect the constraint and we haven't
          // ruled it out

          boolean facingHead = tVector.cos(constraint.normal) > 0.0;

          if (facingHead) {
            // If the constraint is facing the head

            float ph = p.distanceTo(head);
            if (ph < hDistance) {
              headward = p;
              hDistance = ph;
            }

          } else {
            // If the constraint is facing the tail

            float pt = p.distanceTo(tail);
            if (pt < tDistance) {
              tailward = p;
              tDistance = pt;
              twh = p.distanceTo(head);
            }
          }

          if (hDistance < twh) {
            index = i;
            hDistance = (float) constraint
                .distanceTo(facingHead ? tail : head);
          }
        }
      }

      if (index == -1) {
        final Point p;
        
        if (headward != null && tailward != null) {
          p = Point.average(headward, tailward);
        } else if (headward != null) {
          p = headward;
        } else if (tailward != null) {
          p = tailward;
        } else {
          p = Point.average(tail, head);
        }

        if (pointIsInFront(p)) {
          CollisionDetector.setClosestPoint(p);
          return null;
        } else {
          throw new LocalDistMinimum(p);
        }
      } else {
        return edges.get(index);
      }

    } else {
      // If edge is not parallel and doesn't intersect

      double distance = 0.0;
      int index = -1;

      // Check head and tail against all planes
      for (int i = 0; i < edgeCount; i++) {
        final Plane constraint = voronoi.get(i);

        final double h = constraint.distanceTo(head);
        final double t = constraint.distanceTo(tail);

        if (h < distance || t < distance) {
          distance = h < t ? h : t;
          index = i;
        }

      }
      if (index > -1) {
        // If an endpoint failed, return the edge whose constraint was
        // most infringed
        return edges.get(index);
      } else {
        // No endpoint failed
        final double distToTail = distanceTo(tail), distToHead = distanceTo(head);
        if (distToTail > distToHead) {
          CollisionDetector.setClosestPoint(head);
        } else {
          CollisionDetector.setClosestPoint(tail);
        }
        return null;
      }
    }
  }

  private Edge testV(Vertex vert, Matrix matrix) throws LocalDistMinimum {
    final Point tVert = vert.transform(matrix);

    double distance = 0.0;
    int index = -1;

    for (int i = 0; i < edgeCount; i++) {
      Plane constraint = voronoi.get(i);

      double d = constraint.distanceTo(tVert);

      if (d < distance) {
        distance = d;
        index = i;
      }
    }

    if (index > -1) {
      return edges.get(index);
    } else {
      if (!pointIsInFront(tVert)) {
        throw new LocalDistMinimum(tVert);
      } else {
        CollisionDetector.setClosestPoint(tVert);
        return null;
      }
    }
  }

}




Java Source Code List

com.supermercerbros.gameengine.GameActivity.java
com.supermercerbros.gameengine.GameView.java
com.supermercerbros.gameengine.Schooner3D.java
com.supermercerbros.gameengine.TestActivity.java
com.supermercerbros.gameengine.TestMaterials.java
com.supermercerbros.gameengine.TestObjects.java
com.supermercerbros.gameengine.animation.AnimationData.java
com.supermercerbros.gameengine.animation.Keyframe.java
com.supermercerbros.gameengine.animation.MeshAnimation.java
com.supermercerbros.gameengine.armature.ActionData.java
com.supermercerbros.gameengine.armature.Action.java
com.supermercerbros.gameengine.armature.BinarySkeletalVertexModifier.java
com.supermercerbros.gameengine.armature.Bone.java
com.supermercerbros.gameengine.armature.SkeletalVertexModifier.java
com.supermercerbros.gameengine.armature.Skeleton.java
com.supermercerbros.gameengine.collision.Bounds.java
com.supermercerbros.gameengine.collision.Collider.java
com.supermercerbros.gameengine.collision.CollisionDetector.java
com.supermercerbros.gameengine.collision.Collision.java
com.supermercerbros.gameengine.collision.DebugListener.java
com.supermercerbros.gameengine.collision.Edge.java
com.supermercerbros.gameengine.collision.Face.java
com.supermercerbros.gameengine.collision.Feature.java
com.supermercerbros.gameengine.collision.Intersection.java
com.supermercerbros.gameengine.collision.Line.java
com.supermercerbros.gameengine.collision.LocalDistMinimum.java
com.supermercerbros.gameengine.collision.Matrix.java
com.supermercerbros.gameengine.collision.OnCollisionCheckFinishedListener.java
com.supermercerbros.gameengine.collision.Plane.java
com.supermercerbros.gameengine.collision.Point.java
com.supermercerbros.gameengine.collision.Polyhedron.java
com.supermercerbros.gameengine.collision.SphereBounds.java
com.supermercerbros.gameengine.collision.Vector.java
com.supermercerbros.gameengine.collision.Vertex.java
com.supermercerbros.gameengine.debug.JankCatcher.java
com.supermercerbros.gameengine.debug.LoopLog.java
com.supermercerbros.gameengine.engine.Camera.java
com.supermercerbros.gameengine.engine.DataPipe.java
com.supermercerbros.gameengine.engine.EGLContextLostHandler.java
com.supermercerbros.gameengine.engine.Engine.java
com.supermercerbros.gameengine.engine.GameRenderer.java
com.supermercerbros.gameengine.engine.Light.java
com.supermercerbros.gameengine.engine.Normals.java
com.supermercerbros.gameengine.engine.RenderData.java
com.supermercerbros.gameengine.engine.Scene.java
com.supermercerbros.gameengine.engine.Time.java
com.supermercerbros.gameengine.engine.shaders.Material.java
com.supermercerbros.gameengine.engine.shaders.Program.java
com.supermercerbros.gameengine.engine.shaders.ShaderLib.java
com.supermercerbros.gameengine.engine.shaders.Shader.java
com.supermercerbros.gameengine.engine.shaders.VertexModifier.java
com.supermercerbros.gameengine.handlers.OnAnimationCompleteDispatcher.java
com.supermercerbros.gameengine.handlers.OnAnimationCompleteListener.java
com.supermercerbros.gameengine.hud.CoordsConverter.java
com.supermercerbros.gameengine.hud.GameHud.java
com.supermercerbros.gameengine.hud.HudElement.java
com.supermercerbros.gameengine.material.CelShadedMaterial.java
com.supermercerbros.gameengine.material.TexturedMaterial.java
com.supermercerbros.gameengine.math.BezierCurve.java
com.supermercerbros.gameengine.math.Curve.java
com.supermercerbros.gameengine.math.MatrixUtils.java
com.supermercerbros.gameengine.math.Quaternion.java
com.supermercerbros.gameengine.motion.CurveMovement.java
com.supermercerbros.gameengine.motion.MovementData.java
com.supermercerbros.gameengine.motion.Movement.java
com.supermercerbros.gameengine.objects.AnimatedMeshObject.java
com.supermercerbros.gameengine.objects.BasicMaterial.java
com.supermercerbros.gameengine.objects.BonedObject.java
com.supermercerbros.gameengine.objects.GameObject.java
com.supermercerbros.gameengine.objects.Metadata.java
com.supermercerbros.gameengine.parsers.ConstantCurve.java
com.supermercerbros.gameengine.parsers.GameFactory.java
com.supermercerbros.gameengine.parsers.PreBoneData.java
com.supermercerbros.gameengine.parsers.PreObjectData.java
com.supermercerbros.gameengine.parsers.Sch3D.java
com.supermercerbros.gameengine.render.Compositor.java
com.supermercerbros.gameengine.shaders.ProgramSource.java
com.supermercerbros.gameengine.texture.BitmapTexture.java
com.supermercerbros.gameengine.texture.ETC1CompressedTexture.java
com.supermercerbros.gameengine.texture.Texture.java
com.supermercerbros.gameengine.util.BetterDataInputStream.java
com.supermercerbros.gameengine.util.DelayedRunnable.java
com.supermercerbros.gameengine.util.GLES2.java
com.supermercerbros.gameengine.util.IPO.java
com.supermercerbros.gameengine.util.LoopingThread.java
com.supermercerbros.gameengine.util.Toggle.java
com.supermercerbros.gameengine.util.Utils.java