public class RTPolyhedron extends RTShape {
    Vector3D planes_[], transformed_[];
    static Vector3D temp_ = new Vector3D();
    RTPolyhedron(int N) {
        planes_ = new Vector3D[N];
        transformed_ = new Vector3D[N];
        for(int i=0; i<N; ++i) {
            planes_[i] = new Vector3D();
            planes_[i].set(3,-1);
            transformed_[i] = new Vector3D();
        }
    }
    RTPolyhedron(Shape sh) {
        this(sh.faces_.length);
        Vector3D u = new Vector3D(), v = new Vector3D();
        //System.out.println("rtpoly input-a-shapE faces# "+sh.faces_.length);
        for(int i=0; i<sh.faces_.length; ++i) {
            Vector3D 
                P = sh.vertices_[sh.faces_[i][0]].pt,
                Q = sh.vertices_[sh.faces_[i][1]].pt,
                R = sh.vertices_[sh.faces_[i][2]].pt;
            //System.out.println("P "+P);
            //System.out.println("Q "+Q);
            //System.out.println("R "+R);
            Q.minus(P,u);
            R.minus(Q,v);
            u.cross(v,planes_[i]);
            planes_[i].normalize();
            planes_[i].set(3,-planes_[i].dot(Q)); 
            //System.out.println("plane "+planes_[i]);
        }
    }
    final double EPS = 0.0001, INF = 1e40;
    Vector3D enterPlane_ = null;
    double rayHits(Vector3D v, Vector3D w) {
        double enter=0,leave=INF;
        int N = planes_.length;
        for(int i=0; i<N; ++i) {
            Vector3D grad = transformed_[i];
            double gdotv = grad.dot(v),
                gdotw = grad.dot(w);
            if(gdotv>0) { // eye outside
                if(gdotw<-EPS) {
                    double t = -gdotv/gdotw;
                    if(t>enter) { // enter
                        enter = t;
                        enterPlane_ = grad;
                    }
                }
                else return -1; // no see
            }
            else { // inside
                if(gdotw>EPS) {
                    double t = -gdotv/gdotw;
                    if(t<leave)
                        leave = t;
                }
            }
            if(enter>leave)
                return -1;
        }
        return enter;
    }
    void getNormal(double t, Vector3D v, Vector3D w, Vector3D retP, Vector3D retNormal) {
        w.times(t,temp_);
        v.add(temp_,retP);
        retNormal.copy(enterPlane_);
        retNormal.set(3,0);
        retNormal.normalize();
    }
    Matrix3D inverse_ = new Matrix3D();
    void transform(Matrix3D parent) {
        //System.out.println("poly xfor mat "+parent);
        parent.inverse(inverse_);
        //System.out.println("poly xfor inv "+inverse_);
        for(int i=0; i<planes_.length; ++i) 
            inverse_.transformL(planes_[i],transformed_[i]);
        /*
        for(int i=0; i<planes_.length; ++i) 
            System.out.println("poly xfor pla "+transformed_[i]);
        */
    }
}
