/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/07/04, 15:22
!  AUTHOR(S): KOGA, Junichiro
!  File : Plane.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.acviewer.geom;

import javax.media.j3d.BranchGroup;
import javax.vecmath.Point3f;

import org.apache.log4j.Logger;

import ciss.phase_viewer.common.VectorOperations;

/**
 * "面"を表す. 面は, 法線ベクトルと原点を与えれば充分?なはず.
 * 
 * @author
 */
public class Plane extends BranchGroup implements Comparable {
    private Logger logger = Logger.getLogger(Plane.class.getName());
    protected Point3f origin = new Point3f(0.0f, 0.0f, 0.0f);
    protected Point3f normal = new Point3f(0.0f, 0.0f, 1.0f);

    protected Point3f origin_buff = new Point3f(origin);
    protected Point3f normal_buff = new Point3f(normal);

    /**
     * デフォルト値で初期化. 原点: 0,0,0 法線ベクトル: 0,0,1
     */
    public Plane() {
    }

    /**
     * 法線ベクトルを与えて初期化. 一応, 規格化されていることを想定.
     * 
     * @param normal
     *            法線ベクトル
     */
    public Plane(Point3f normal) {
        this.normal = new Point3f(normal);
        normalizeNorm();
    }

    /**
     * 法線ベクトルも原点も与えて初期化.
     * 
     * @param normal
     *            法線ベクトル
     * @param origin
     *            原点
     */
    public Plane(Point3f normal, Point3f origin) {
        this.normal = new Point3f(normal);
        this.origin = new Point3f(origin);
        normalizeNorm();
    }

    /**
     * 法線ベクトルを規格化する.
     */
    public void normalizeNorm() {
        double[] test = new double[] { (double) normal.x, (double) normal.y,
                (double) normal.z };
        double res = VectorOperations.norm(test);
        if (res == 0) {
            normal.x = 0;
            normal.y = 0;
            normal.z = 1;
            return;
        }
        normal.x = normal.x / ((float) res);
        normal.y = normal.y / ((float) res);
        normal.z = normal.z / ((float) res);
    }

    /**
     * この面との間の距離をゲット. 正負によって, どちら側かも判定可. なはず.
     */
    public float getDistanceFrom(Point3f from) {
        double[] foo = new double[] { (double) from.x, (double) from.y,
                (double) from.z };
        double[] normd = new double[] { (double) normal.x, (double) normal.y,
                (double) normal.z };
        double[] origd = new double[] { (double) origin.x, (double) origin.y,
                (double) origin.z };
        return (float) VectorOperations.getDistanceFromPlane(foo, normd, origd,
                true);
    }

    /**
     * この面の法線ベクトルを返す.
     * 
     * @return この面の法線ベクトル
     */
    public Point3f getNormalVector() {
        return this.normal;
    }

    /**
     * この面の原点を返す.
     * 
     * @return この面の原点
     */
    public Point3f getOrigin() {
        return this.origin;
    }

    /**
     * 原点を新たに設定しなおす
     * 
     * @param origin
     */
    public void setOrigin(Point3f origin) {
        this.origin = origin;
    }

    /**
     * 法線ベクトルを新たに設定しなおす. 規格化は勝手に行う.
     * 
     * @param normal
     *            法線ベクトル
     */
    public void setNormalVector(Point3f normal) {
        this.normal = normal;
        normalizeNorm();
    }

    /**
     * "origin"が原点から遠い方が大きい
     * 
     * @param 比較元
     * @return 比較元よりも原点が遠い場合+1, 近い場合-1, 同じな場合0を返す.
     */
    public int compareTo(Object o) {
        if (!(o instanceof Plane)) {
            return -1;
        }
        Plane pl = (Plane) o;
        Point3f orig = pl.getOrigin();
        float disto = orig.distance(new Point3f());
        float distthis = origin.distance(new Point3f());
        if (distthis - disto < 0) {
            return -1;
        } else if (disto == distthis) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * @return 原点からの距離が同じな場合true
     */
    public boolean equals(Object obj) {
        if (obj == this)
            return true; // 常に.

        if (!(obj instanceof Plane)) {
            return false;
        }
        Plane pl = (Plane) obj;
        Point3f orig = pl.getOrigin();
        float disto = orig.distance(new Point3f());
        float distthis = origin.distance(new Point3f());
        return disto == distthis;
    }

}
