Package nu3a.collision

Source Code of nu3a.collision.N3Ray

/*
*  Copyright (c) 2003 Jorge García, Unai Aguilera
*
*  This file is part of Nu3A.
*
*   Nu3A is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.

*   Nu3A is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with Nu3A.  If not, see <http://www.gnu.org/licenses/>.
*
*
*  Authors: Jorge García <bardok@gmail.com>, Unai Aguilera <gkalgan@gmail.com>
*/

package nu3a.collision;

import nu3a.geometry.N3Point2D;
import nu3a.geometry.N3Point3D;
import nu3a.geometry.N3Polygon;
import nu3a.math.N3Vector3D;

/**
* Esta clase define un rayo finito que puede ser utilizado para seleccionar
* objetos mediante "picking". El rayo esta determinado mediante dos puntos, el
* punto origen y el punto destino.
*/
public class N3Ray implements N3Collisionable {
  /**
   * Punto origen del rayo.
   */
  protected N3Point3D src;
  /**
   * Punto destino del rayo.
   */
  protected N3Point3D dest;

  // Vector del rayo
  private N3Vector3D d;

  /**
   * Constructor de la clase. Permite obtener un rayo definido entre los
   * puntos origen y destino indicados.
   *
   * @param src
   *            Punto origen del rayo.
   * @param dest
   *            Punto destino del rayo.
   */
  public N3Ray(N3Point3D src, N3Point3D dest) {
    this.src = new N3Point3D(src.x, src.y, src.z);
    this.dest = new N3Point3D(dest.x, dest.y, dest.z);
    d = new N3Vector3D(dest.x - src.x, dest.y - src.y, dest.z - src.z);
    d.normalize();
  }

  private boolean testAABB(N3AABB aabb) {
    float t1, t2;
    float tNear = -100000000000.0f;
    float tFar = 100000000000.0f;
    // Comprobamos si el rayo es paralelo al eje X, si es asi y no esta
    // entre los planos de la caja no hay colisi�n.
    if (src.x == dest.x && !(src.x > aabb.minX && src.x < aabb.maxX))
      return false;
    else {
      t1 = (aabb.minX - src.x) / (dest.x - src.x);
      t2 = (aabb.maxX - src.x) / (dest.x - src.x);
      if (t1 > t2) {
        float temp = t1;
        t1 = t2;
        t2 = temp;
      }
      if (t1 > tNear)
        tNear = t1;
      if (t2 < tFar)
        tFar = t2;
      if (tNear > tFar)
        return false;
      if (tFar < 0)
        return false;
    }

    if (src.y == dest.y && !(src.y > aabb.minY && src.y < aabb.maxY))
      return false;
    else {
      t1 = (aabb.minY - src.y) / (dest.y - src.y);
      t2 = (aabb.maxY - src.y) / (dest.y - src.y);
      if (t1 > t2) {
        float temp = t1;
        t1 = t2;
        t2 = temp;
      }
      if (t1 > tNear)
        tNear = t1;
      if (t2 < tFar)
        tFar = t2;
      if (tNear > tFar)
        return false;
      if (tFar < 0)
        return false;
    }

    if (src.z == dest.z && !(src.z > aabb.minZ && src.z < aabb.maxZ))
      return false;
    else {
      t1 = (aabb.minZ - src.z) / (dest.z - src.z);
      t2 = (aabb.maxZ - src.z) / (dest.z - src.z);
      if (t1 > t2) {
        float temp = t1;
        t1 = t2;
        t2 = temp;
      }
      if (t1 > tNear)
        tNear = t1;
      if (t2 < tFar)
        tFar = t2;
      if (tNear > tFar)
        return false;
      if (tFar < 0)
        return false;
    }
    return true;
  }

  private boolean testPolygon(N3Polygon poly) {
    // Punto en el interior del poligono proyectado.
    N3Point2D inside;
    // Obtenemos el plano del poligono representado de la forma Ax + By +Cz
    // +D = 0
    N3Vector3D polyNormal = poly.getPolygonNormal();
    N3Point3D v = (N3Point3D) poly.getVertex(0);
    float polyD = -(polyNormal.x * v.x + polyNormal.y * v.y + polyNormal.z
        * v.z);
    // Primero comprobamos si hay intersecci�n entre el rayo y el plano
    // Substituimos (x,y,z)=(px,py,pz) + t(dx,dy,dz) en la ecuacion del
    // plano.
    // despejamos t = -(Apx + Bpy + Cpz + D)/(Adx + Bdy + Cdz)
    float s = (polyNormal.x * d.x + polyNormal.y * d.y + polyNormal.z * d.z);
    if (s == 0)
      return false;
    float t = -(polyNormal.x * src.x + polyNormal.y * src.y + polyNormal.z
        * src.z + polyD)
        / s;
    if (t <= 0)
      return false;

    // Ahora hay que comprobar si el punto de corte del rayo con el plano,
    // esta dentro del poligono.
    // Obtenemos el punto de corte con el plano.
    N3Point3D p3D = new N3Point3D(src.x + t * d.x, src.y + t * d.y, src.z
        + t * d.z);

    // Utilizamos el metodo de los half-spaces proyectando el pol�gono y el
    // punto ortograficamente en 2D,
    // seleccionando como plano de proyecci�n aquel en el que el pol�gono
    // tenga un mayor �rea.
    // El �rea es proporcional al las componentes A,B,C del vector normal
    // del pol�gono.
    N3Point2D p2D;
    // Indica en que plano hemos proyectado. 0 = yz, 1 = zx, 2 = xy.
    int plane;
    if (Math.abs(polyNormal.x) > Math.abs(polyNormal.y)
        && Math.abs(polyNormal.x) > Math.abs(polyNormal.z)) {
      // Si es |A| proyectamos en el plano yz.
      p2D = new N3Point2D(p3D.y, p3D.z);
      plane = 0;
    } else if (Math.abs(polyNormal.y) > Math.abs(polyNormal.x)
        && Math.abs(polyNormal.y) > Math.abs(polyNormal.z)) {
      // Si es |B| proyectamos en el plano zx.
      p2D = new N3Point2D(p3D.z, p3D.x);
      plane = 1;
    } else {
      // Si es |C| proyectamos en el plano xy.
      p2D = new N3Point2D(p3D.x, p3D.y);
      plane = 2;
    }

    // Para cada arista del poligono calculamos la ecuaci�n e(u,v)= au + bv
    // + c = 0 que representa un divisi�n del espacio en 2
    // partes, "half-space", el pol�gono queda definido por la intersecci�n
    // de todos ellos.
    // Para un poligono definido en sentido antihorario un punto esta dentro
    // de el si para todos las aristas
    // e < 0.
    for (int i = 0; i < poly.getSides(); i++) {
      // Proyectamos los puntos de la arista actual.
      N3Point3D v13D = (N3Point3D) poly.getVertex(i);
      N3Point3D v23D;
      N3Point2D v1, v2;
      if (i == poly.getSides() - 1)
        v23D = (N3Point3D) poly.getVertex(0);
      else
        v23D = (N3Point3D) poly.getVertex(i + 1);
      if (plane == 0) {
        v1 = new N3Point2D(v13D.y, v13D.z);
        v2 = new N3Point2D(v23D.y, v23D.z);
        inside = new N3Point2D(
            (((N3Point3D) poly.getVertex(0)).y
                + ((N3Point3D) poly.getVertex(1)).y + ((N3Point3D) poly
                .getVertex(2)).y) / 3.0f,
            (((N3Point3D) poly.getVertex(0)).z
                + ((N3Point3D) poly.getVertex(1)).z + ((N3Point3D) poly
                .getVertex(2)).z) / 3.0f);
      } else if (plane == 1) {
        v1 = new N3Point2D(v13D.z, v13D.x);
        v2 = new N3Point2D(v23D.z, v23D.x);
        inside = new N3Point2D(
            (((N3Point3D) poly.getVertex(0)).z
                + ((N3Point3D) poly.getVertex(1)).z + ((N3Point3D) poly
                .getVertex(2)).z) / 3.0f,
            (((N3Point3D) poly.getVertex(0)).x
                + ((N3Point3D) poly.getVertex(1)).x + ((N3Point3D) poly
                .getVertex(2)).x) / 3.0f);
      } else {
        v1 = new N3Point2D(v13D.x, v13D.y);
        v2 = new N3Point2D(v23D.x, v23D.y);
        inside = new N3Point2D(
            (((N3Point3D) poly.getVertex(0)).x
                + ((N3Point3D) poly.getVertex(1)).x + ((N3Point3D) poly
                .getVertex(2)).x) / 3.0f,
            (((N3Point3D) poly.getVertex(0)).y
                + ((N3Point3D) poly.getVertex(1)).y + ((N3Point3D) poly
                .getVertex(2)).y) / 3.0f);
      }

      // Obtenemos la representaci�n de la forma: au + bv + c = 0
      float a = (v1.y - v2.y);
      float b = (v2.x - v1.x);
      float c = (v1.x * v2.y - v2.x * v1.y);
      // Tenemos que comprobar si el poligono esta en sentido horario o
      // antihorario
      // obtenemos el producto vectorial entre el vector del rayo y la
      // normal del plano, si es negativo
      // esta dado la vuelta.
      float dir = d.dotProduct(polyNormal);
      if (dir > 0) {
        a = -a;
        b = -b;
        c = -c;
      }
      // Elegimos el signo de la comparaci�n
      if (a * inside.x + b * inside.y + c < 0) {
        if (a * p2D.x + b * p2D.y + c > 0)
          return false;
      } else {
        if (a * p2D.x + b * p2D.y + c < 0)
          return false;
      }
    }
    return true;
  }

  public boolean test(N3Collisionable c) {
    if (c instanceof N3AABB)
      return testAABB((N3AABB) c);
    if (c instanceof N3Polygon)
      return testPolygon((N3Polygon) c);
    return false;
  }

  public void setCollisionable(boolean c) {
  }

  public boolean getCollisionable() {
    return true;
  }

  public String toString() {
    String s = "";
    s += src + " --> " + dest;
    return s;
  }
}
TOP

Related Classes of nu3a.collision.N3Ray

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.