/*
 * This program 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 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 PURPOUSE. See the GNU
 * General Public License for more details.
 *
 * You should have recieved a copy of the GNU General Public License
 * along with this program; if not write to the Free Software
 * Foundation, inc., 59 Temple Place, Suite 330, Boston MA 02111-1307
 * USA
 */
package j3d;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
/**
 * Insert the type's description here.
 *
 * @author: Yuriy Mikhaylovskiy
 */

public class lib3D{

  public static float[] PL3T(_Point p0, _Point p1, _Point p2){
    /*float[] a = new float[3];
    float[] b = new float[3];
    float[] c = new float[3];
    float[] p = new float[4];
    a[0]=p1.x;
    a[1]=p1.y;
    a[2]=p1.z;
    b[0]=p2.x;
    b[1]=p2.y;
    b[2]=p2.z;
    c[0]=p3.x;
    c[1]=p3.y;
    c[2]=p3.z;
    for(int i=0; i<0; i++){
      b[i]-=a[i];
      c[i]-=a[i];
    }
    p[0]=b[1]*c[2]-c[1]*b[2];
    p[1]=-b[0]*c[2]+c[1]*b[2];
    p[2]=b[0]*c[1]-c[0]*b[2];
    p[3]=-a[0]*p[0]+a[1]*p[1]-a[2]*p[2];*/
    float[] p = new float[4];
    float a1 = (p1.y-p0.y)*(p2.z-p0.z);
    float a2 = (p1.z-p0.z)*(p2.x-p0.x);
    float a3 = (p1.x-p0.x)*(p2.y-p0.y);
    float a4 = (p1.y-p0.y)*(p2.x-p0.x);
    float a5 = (p1.z-p0.z)*(p2.y-p0.y);
    float a6 = (p1.x-p0.x)*(p2.z-p0.z);
    p[0]=a1-a5;
    p[1]=a2-a6;
    p[2]=a3-a4;
    p[3]=p0.y*a6+p0.x*a5+p0.z*a4-p0.z*a3-p0.y*a2-p0.x*a1;
    return p;
  }

  public static float[] PL3T_LINE(_Point p1, _Point p2, _Point p3, _Point t1, _Point t2){
    float[] p = PL3T(p1,p2,p3);
    float[] xyz = new float[3];
    if(t1.x==t2.x && t1.z==t2.z){
      xyz[0]=t1.x;
      xyz[1]=(-p[0]*t1.x-p[2]*t1.z-p[3])/p[1];
      xyz[2]=t1.z;
    }else if(t1.y==t2.y && t1.z==t2.z){
      xyz[0]=(-p[1]*t1.y-p[2]*t1.z-p[3])/p[0];
      xyz[1]=t1.y;
      xyz[2]=t1.z;
    }else if(t1.x==t2.x && t1.y==t2.y){
      xyz[0]=t1.x;
      xyz[1]=t1.y;
      xyz[2]=(-p[0]*t1.x-p[1]*t1.y-p[3])/p[2];
    }
    if(Float.isNaN(xyz[0]) || Float.isNaN(xyz[1]) || Float.isNaN(xyz[2])) {return null;}
    float xmin = Math.min(p1.x,p2.x);
    float xmax = Math.max(p1.x,p2.x);
    float ymin = Math.min(p1.y,p2.y);
    float ymax = Math.max(p1.y,p2.y);
    float zmin = Math.min(p1.z,p2.z);
    float zmax = Math.max(p1.z,p2.z);
    xmin = Math.min(xmin,p3.x);
    xmax = Math.max(xmax,p3.x);
    ymin = Math.min(ymin,p3.y);
    ymax = Math.max(ymax,p3.y);
    zmin = Math.min(zmin,p3.z);
    zmax = Math.max(zmax,p3.z);
    if(!(xmin<=xyz[0] && xmax>=xyz[0]) || !(ymin<=xyz[1] && ymax>=xyz[1]) || !(zmin<=xyz[2] && zmax>=xyz[2])) return null;
    GeneralPath gp_xy = new GeneralPath();
    gp_xy.reset();
    gp_xy.moveTo(p1.x,p1.y);
    gp_xy.lineTo(p2.x,p2.y);
    gp_xy.lineTo(p3.x,p3.y);
    gp_xy.closePath();
    if(gp_xy.contains(xyz[0],xyz[1])) return xyz;
    else if(Line2D.Float.ptLineDist(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y)!=0 && xmin<=xyz[0] && xmax>=xyz[0] && ymin<=xyz[1] && ymax>=xyz[1]){
      if((p1.x==p2.x || p1.y==p2.y) && Line2D.Float.ptLineDist(p1.x,p1.y,p2.x,p2.y,xyz[0],xyz[1])==0)return xyz;
      if((p1.x==p3.x || p1.y==p3.y) && Line2D.Float.ptLineDist(p1.x,p1.y,p3.x,p3.y,xyz[0],xyz[1])==0)return xyz;
      if((p3.x==p2.x || p3.y==p2.y) && Line2D.Float.ptLineDist(p2.x,p2.y,p3.x,p3.y,xyz[0],xyz[1])==0)return xyz;
    }
    GeneralPath gp_xz = new GeneralPath();
    gp_xz.reset();
    gp_xz.moveTo(p1.x,p1.z);
    gp_xz.lineTo(p2.x,p2.z);
    gp_xz.lineTo(p3.x,p3.z);
    gp_xz.closePath();
    if(gp_xz.contains(xyz[0],xyz[2])) return xyz;
    else if(Line2D.Float.ptLineDist(p1.x,p1.z,p2.x,p2.z,p3.x,p3.z)!=0 && xmin<=xyz[0] && xmax>=xyz[0] && zmin<=xyz[2] && zmax>=xyz[2]){
      if((p1.x==p2.x || p1.z==p2.z) && Line2D.Float.ptLineDist(p1.x,p1.z,p2.x,p2.z,xyz[0],xyz[2])==0)return xyz;
      if((p1.x==p3.x || p1.z==p3.z) && Line2D.Float.ptLineDist(p1.x,p1.z,p3.x,p3.z,xyz[0],xyz[2])==0)return xyz;
      if((p3.x==p2.x || p3.z==p2.z) && Line2D.Float.ptLineDist(p2.x,p2.z,p3.x,p3.z,xyz[0],xyz[2])==0)return xyz;
    }
    GeneralPath gp_yz = new GeneralPath();
    gp_yz.reset();
    gp_yz.moveTo(p1.y,p1.z);
    gp_yz.lineTo(p2.y,p2.z);
    gp_yz.lineTo(p3.y,p3.z);
    gp_yz.closePath();
    if(gp_yz.contains(xyz[1],xyz[2])) return xyz;
    else if(Line2D.Float.ptLineDist(p1.y,p1.z,p2.y,p2.z,p3.y,p3.z)!=0 && ymin<=xyz[1] && ymax>=xyz[1] && zmin<=xyz[2] && zmax>=xyz[2]){
      if((p1.y==p2.y || p1.z==p2.z) && Line2D.Float.ptLineDist(p1.y,p1.z,p2.y,p2.z,xyz[1],xyz[2])==0)return xyz;
      if((p1.y==p3.y || p1.z==p3.z) && Line2D.Float.ptLineDist(p1.y,p1.z,p3.y,p3.z,xyz[1],xyz[2])==0)return xyz;
      if((p3.y==p2.y || p3.z==p2.z) && Line2D.Float.ptLineDist(p2.y,p2.z,p3.y,p3.z,xyz[1],xyz[2])==0)return xyz;
    }
    return null;
  }

  public static float[] PL3T_LINE2(_Point p1, _Point p2, _Point p3, _Point t1, _Point t2){
    float[] p = PL3T(p1,p2,p3);
    float[] xyz = new float[3];
    if(t1.x==t2.x && t1.z==t2.z){
      xyz[0]=t1.x;
      xyz[1]=(-p[0]*t1.x-p[2]*t1.z-p[3])/p[1];
      xyz[2]=t1.z;
    }else if(t1.y==t2.y && t1.z==t2.z){
      xyz[0]=(-p[1]*t1.y-p[2]*t1.z-p[3])/p[0];
      xyz[1]=t1.y;
      xyz[2]=t1.z;
    }else if(t1.x==t2.x && t1.y==t2.y){
      xyz[0]=t1.x;
      xyz[1]=t1.y;
      xyz[2]=(-p[0]*t1.x-p[1]*t1.y-p[3])/p[2];
    }
    if(Float.isNaN(xyz[0]) || Float.isNaN(xyz[1]) || Float.isNaN(xyz[2])) {return null;}
    float xmin = Math.min(p1.x,p2.x);
    float xmax = Math.max(p1.x,p2.x);
    float ymin = Math.min(p1.y,p2.y);
    float ymax = Math.max(p1.y,p2.y);
    float zmin = Math.min(p1.z,p2.z);
    float zmax = Math.max(p1.z,p2.z);
    xmin = Math.min(xmin,p3.x);
    xmax = Math.max(xmax,p3.x);
    ymin = Math.min(ymin,p3.y);
    ymax = Math.max(ymax,p3.y);
    zmin = Math.min(zmin,p3.z);
    zmax = Math.max(zmax,p3.z);
    if(!(xmin<=xyz[0] && xmax>=xyz[0]) || !(ymin<=xyz[1] && ymax>=xyz[1]) || !(zmin<=xyz[2] && zmax>=xyz[2])) return null;
    if(Line2D.Float.ptLineDist(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y)!=0 && xmin<=xyz[0] && xmax>=xyz[0] && ymin<=xyz[1] && ymax>=xyz[1]){
      if((p1.x==p2.x || p1.y==p2.y) && Line2D.Float.ptLineDist(p1.x,p1.y,p2.x,p2.y,xyz[0],xyz[1])==0)return xyz;
      if((p1.x==p3.x || p1.y==p3.y) && Line2D.Float.ptLineDist(p1.x,p1.y,p3.x,p3.y,xyz[0],xyz[1])==0)return xyz;
      if((p3.x==p2.x || p3.y==p2.y) && Line2D.Float.ptLineDist(p2.x,p2.y,p3.x,p3.y,xyz[0],xyz[1])==0)return xyz;
      if(Line2D.Float.linesIntersect(p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,xyz[0],xyz[1]))return null;
      if(Line2D.Float.linesIntersect(p1.x,p1.y,p3.x,p3.y,p2.x,p2.y,xyz[0],xyz[1]))return null;
      if(Line2D.Float.linesIntersect(p3.x,p3.y,p2.x,p2.y,p1.x,p1.y,xyz[0],xyz[1]))return null;
      return xyz;
    }
    if(Line2D.Float.ptLineDist(p1.x,p1.z,p2.x,p2.z,p3.x,p3.z)!=0 && xmin<=xyz[0] && xmax>=xyz[0] && zmin<=xyz[2] && zmax>=xyz[2]){
      if((p1.x==p2.x || p1.z==p2.z) && Line2D.Float.ptLineDist(p1.x,p1.z,p2.x,p2.z,xyz[0],xyz[2])==0)return xyz;
      if((p1.x==p3.x || p1.z==p3.z) && Line2D.Float.ptLineDist(p1.x,p1.z,p3.x,p3.z,xyz[0],xyz[2])==0)return xyz;
      if((p3.x==p2.x || p3.z==p2.z) && Line2D.Float.ptLineDist(p2.x,p2.z,p3.x,p3.z,xyz[0],xyz[2])==0)return xyz;
      if(Line2D.Float.linesIntersect(p1.x,p1.z,p2.x,p2.z,p3.x,p3.z,xyz[0],xyz[2]))return null;
      if(Line2D.Float.linesIntersect(p1.x,p1.z,p3.x,p3.z,p2.x,p2.z,xyz[0],xyz[2]))return null;
      if(Line2D.Float.linesIntersect(p3.x,p3.z,p2.x,p2.z,p1.x,p1.z,xyz[0],xyz[2]))return null;
      return xyz;
    }
    if(Line2D.Float.ptLineDist(p1.y,p1.z,p2.y,p2.z,p3.y,p3.z)!=0 && ymin<=xyz[1] && ymax>=xyz[1] && zmin<=xyz[2] && zmax>=xyz[2]){
      if((p1.y==p2.y || p1.z==p2.z) && Line2D.Float.ptLineDist(p1.y,p1.z,p2.y,p2.z,xyz[1],xyz[2])==0)return xyz;
      if((p1.y==p3.y || p1.z==p3.z) && Line2D.Float.ptLineDist(p1.y,p1.z,p3.y,p3.z,xyz[1],xyz[2])==0)return xyz;
      if((p3.y==p2.y || p3.z==p2.z) && Line2D.Float.ptLineDist(p2.y,p2.z,p3.y,p3.z,xyz[1],xyz[2])==0)return xyz;
      if(Line2D.Float.linesIntersect(p1.y,p1.z,p2.y,p2.z,p3.y,p3.z,xyz[1],xyz[2]))return null;
      if(Line2D.Float.linesIntersect(p1.y,p1.z,p3.y,p3.z,p2.y,p2.z,xyz[1],xyz[2]))return null;
      if(Line2D.Float.linesIntersect(p3.y,p3.z,p2.y,p2.z,p1.y,p1.z,xyz[1],xyz[2]))return null;
      return xyz;
    }
    return null;
  }

  public static float[] PL3T_LINE1(_Point p1, _Point p2, _Point p3, _Point t1, _Point t2){
    float[] p = PL3T(p1,p2,p3);
    float[] xyz = new float[3];
    if(t1.x==t2.x && t1.z==t2.z){
      xyz[0]=t1.x;
      xyz[1]=(-p[0]*t1.x-p[2]*t1.z-p[3])/p[1];
      xyz[2]=t1.z;
    }else if(t1.y==t2.y && t1.z==t2.z){
      xyz[0]=(-p[1]*t1.y-p[2]*t1.z-p[3])/p[0];
      xyz[1]=t1.y;
      xyz[2]=t1.z;
    }else if(t1.x==t2.x && t1.y==t2.y){
      xyz[0]=t1.x;
      xyz[1]=t1.y;
      xyz[2]=(-p[0]*t1.x-p[1]*t1.y-p[3])/p[2];
    }
    float xmin = Math.min(p1.x,p2.x);
    float xmax = Math.max(p1.x,p2.x);
    float ymin = Math.min(p1.y,p2.y);
    float ymax = Math.max(p1.y,p2.y);
    float zmin = Math.min(p1.z,p2.z);
    float zmax = Math.max(p1.z,p2.z);
    xmin = Math.min(xmin,p3.x);
    xmax = Math.max(xmax,p3.x);
    ymin = Math.min(ymin,p3.y);
    ymax = Math.max(ymax,p3.y);
    zmin = Math.min(zmin,p3.z);
    zmax = Math.max(zmax,p3.z);
    float dx = Math.abs(xmax-xmin);
    float dy = Math.abs(ymax-ymin);
    float dz = Math.abs(zmax-zmin);
    double p1x,p1y,p2x,p2y,p3x,p3y,x1,y1,x2,y2,x3,y3;
    double sin,cos,r;
    if(((dx<dy && dy<dz) || (dx<dz && dz<dy)) && t1.x!=t2.x){
      p1x=p1.y-xyz[1];
      p1y=p1.z-xyz[2];
      p2x=p2.y-xyz[1];
      p2y=p2.z-xyz[2];
      p3x=p3.y-xyz[1];
      p3y=p3.z-xyz[2];
      r=Math.sqrt(p1x*p1x+p1y*p1y);
      cos=p1x/r;
      sin=p1y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p2x*p2x+p2y*p2y);
      cos=p2x/r;
      sin=p2y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p3x*p3x+p3y*p3y);
      cos=p3x/r;
      sin=p3y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
    }else if(((dy<dx && dx<dz) || (dy<dz && dz<dx)) && t1.y!=t2.y){
      p1x=p1.y-xyz[0];
      p1y=p1.z-xyz[2];
      p2x=p2.y-xyz[0];
      p2y=p2.z-xyz[2];
      p3x=p3.y-xyz[0];
      p3y=p3.z-xyz[2];
      r=Math.sqrt(p1x*p1x+p1y*p1y);
      cos=p1x/r;
      sin=p1y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p2x*p2x+p2y*p2y);
      cos=p2x/r;
      sin=p2y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p3x*p3x+p3y*p3y);
      cos=p3x/r;
      sin=p3y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
    }else if(((dz<dx && dx<dy) || (dz<dy && dy<dx)) && t1.z!=t2.z){
      p1x=p1.x-xyz[0];
      p1y=p1.y-xyz[1];
      p2x=p2.x-xyz[0];
      p2y=p2.y-xyz[1];
      p3x=p3.x-xyz[0];
      p3y=p3.y-xyz[1];
      r=Math.sqrt(p1x*p1x+p1y*p1y);
      cos=p1x/r;
      sin=p1y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p2x*p2x+p2y*p2y);
      cos=p2x/r;
      sin=p2y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
      r=Math.sqrt(p3x*p3x+p3y*p3y);
      cos=p3x/r;
      sin=p3y/r;
      x1=p1x*cos+p1y*sin;
      x2=p2x*cos+p2y*sin;
      x3=p3x*cos+p3y*sin;
      if((x1==x2 && x1==0) || (x1==x3 && x1==0) || (x3==x2 && x3==0)) return xyz;
      if((x1<=0 && x2<=0 && x3<=0) || (x1>=0 && x2>=0 && x3>=0)) return null;
    }
    return xyz;
  }

}