package acousticfield3d.algorithms;

import acousticfield3d.gui.MainForm;
import acousticfield3d.gui.misc.ForcePlotsFrame;
import acousticfield3d.math.M;
import acousticfield3d.math.Vector2f;
import acousticfield3d.math.Vector3f;
import acousticfield3d.renderer.Renderer;
import java.nio.FloatBuffer;

/**
 *
 * @author Asier
 */
public class CachedPointFieldCalc {
    Vector3f position = new Vector3f();
    boolean isReflector;
    
    Vector2f pre = new Vector2f();
    Vector2f gx = new Vector2f(), gy = new Vector2f(), gz = new Vector2f();
    Vector2f gxy = new Vector2f(), gxz = new Vector2f(), gyz = new Vector2f();
    Vector2f gxx = new Vector2f(), gyy = new Vector2f(), gzz = new Vector2f();
    
    Vector2f gxxx = new Vector2f(), gyyy = new Vector2f(), gzzz = new Vector2f();
    Vector2f gxyy = new Vector2f(), gxzz = new Vector2f();
    Vector2f gyxx = new Vector2f(), gyzz = new Vector2f();
    Vector2f gzxx = new Vector2f(), gzyy = new Vector2f();
         
    Vector2f swap = new Vector2f(), tmp = new Vector2f();
    Vector3f nor = new Vector3f();
    Vector3f diffVec = new Vector3f();
    Vector3f diffVecS = new Vector3f();
    Vector3f tPos = new Vector3f();
    
    double K1, K2;
    double M1, M2;
    
    final int nTotalTrans, nTrans;
    final float h;
    final boolean useDirectivity;
    
    double[] a,b, ka, kb; //per transducers
    double[] xa,xb, xka, xkb;
    double[] ya,yb, yka, ykb;
    double[] za,zb, zka, zkb;
    
    double[] xya,xyb, xyka, xykb;
    double[] xza,xzb, xzka, xzkb;
    double[] yza,yzb, yzka, yzkb;
    double[] xxa,xxb, xxka, xxkb;
    double[] yya,yyb, yyka, yykb;
    double[] zza,zzb, zzka, zzkb;
    
    double[] xxxa,xxxb, xxxka, xxxkb;
    double[] yyya,yyyb, yyyka, yyykb;
    double[] zzza,zzzb, zzzka, zzzkb;
    double[] xyya,xyyb, xyyka, xyykb;
    double[] xzza,xzzb, xzzka, xzzkb;
    double[] yxxa,yxxb, yxxka, yxxkb;
    double[] yzza,yzzb, yzzka, yzzkb;
    double[] zxxa,zxxb, zxxka, zxxkb;
    double[] zyya,zyyb, zyyka, zyykb;

    double lowPressureK = 1;
    
    public static CachedPointFieldCalc create(final Vector3f pos, MainForm mf){
        //final boolean reflection = mf.simulation.isReflection();
        //final boolean directivity = !mf.miscPanel.isAnalyticalNoDirShaders();
        final boolean reflection = false;
        final boolean directivity = true;
        
        final float h = mf.simulation.getWavelenght()/ mf.miscPanel.getFiniteDiffH();
        CachedPointFieldCalc cp = new CachedPointFieldCalc(pos, reflection,directivity, h, mf.renderer);
        return cp;        
    }
    
    public CachedPointFieldCalc(final Vector3f pos, boolean reflectorEnabled, boolean useDirectivity, float h, Renderer r) {
        this.isReflector = reflectorEnabled;
        this.useDirectivity = useDirectivity;
        this.h = h;
        nTotalTrans = r.getnTransducers();
        nTrans = reflectorEnabled ? nTotalTrans/2 : nTotalTrans;
        position.set( pos );
    }

    public void setPosition(Vector3f position) {
        this.position = position;
    }

    public Vector3f getPosition() {
        return position;
    }

    
    public int getNTrans() {
        return nTrans;
    }

    public double getLowPressureK() {
        return lowPressureK;
    }

    public void setLowPressureK(double lowPressureK) {
        this.lowPressureK = lowPressureK;
    }
    
    //<editor-fold defaultstate="collapsed" desc="pressure">
    
    public void updatePressure(final double[] v){
        pre.set(0,0);
        for(int i = 0; i < nTrans; ++i){
            final double cosP = Math.cos( v[i] );
            final double sinP = Math.sin( v[i] );
            a[i] = ka[i]*cosP - kb[i]*sinP;
            b[i] = ka[i]*sinP + kb[i]*cosP;
            pre.x += a[i];
            pre.y += b[i];
        }
    }
    
    public void evalField(Vector2f field){
        field.set( pre );
    }
    public double evalPressure(){
        return pre.length();
    }
    public void gradientPressure(double[] g){
        final double p = pre.length();
        final double aDivP = pre.x / p;
        final double bDivP = pre.y / p;
        for(int i = 0; i < nTrans; ++i){
            g[i] = bDivP * a[i] - aDivP * b[i];
        }
    }
//</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="gorkov">  
   
    public void updateGorkov(final double[] v){
        pre.set(0);
        gx.set(0); gy.set(0); gz.set(0);
        for(int i = 0; i < nTrans; ++i){
            final double cosP = Math.cos( v[i] );
            final double sinP = Math.sin( v[i] );
            
            a[i] = ka[i]*cosP - kb[i]*sinP;
            b[i] = ka[i]*sinP + kb[i]*cosP;
            pre.x += a[i]; pre.y += b[i];
            
            xa[i] = xka[i]*cosP - xkb[i]*sinP;
            xb[i] = xka[i]*sinP + xkb[i]*cosP;
            gx.x += xa[i]; gx.y += xb[i];
            
            ya[i] = yka[i]*cosP - ykb[i]*sinP;
            yb[i] = yka[i]*sinP + ykb[i]*cosP;
            gy.x += ya[i]; gy.y += yb[i];
            
            za[i] = zka[i]*cosP - zkb[i]*sinP;
            zb[i] = zka[i]*sinP + zkb[i]*cosP;
            gz.x += za[i]; gz.y += zb[i];
        }
    }
    
    public double evalGorkov(){
        return  M1 * lowPressureK * pre.dot(pre) - M2*( gx.dot(gx) + gy.dot(gy) + gz.dot(gz));
    }
    public void gradientGorkov(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * lowPressureK *( pre.x*-b[i] + pre.y*a[i]) - 
                   K2*( gx.x*-xb[i]+gx.y*xa[i] + gy.x*-yb[i]+gy.y*ya[i] + gz.x*-zb[i]+gz.y*za[i]);
        }
    }
    //</editor-fold>
   
    //<editor-fold defaultstate="collapsed" desc="gorkovGradient">  
 
    public void updateGorkovGradient(final double[] v){
        pre.set(0);
        gx.set(0); gy.set(0); gz.set(0);
        gxx.set(0); gyy.set(0); gzz.set(0);
        gxy.set(0); gxz.set(0); gyz.set(0);
        for(int i = 0; i < nTrans; ++i){
            final double cosP = Math.cos( v[i] );
            final double sinP = Math.sin( v[i] );
            
            a[i] = ka[i]*cosP - kb[i]*sinP;
            b[i] = ka[i]*sinP + kb[i]*cosP;
            pre.x += a[i]; pre.y += b[i];
            
            xa[i] = xka[i]*cosP - xkb[i]*sinP;
            xb[i] = xka[i]*sinP + xkb[i]*cosP;
            gx.x += xa[i]; gx.y += xb[i];
            
            ya[i] = yka[i]*cosP - ykb[i]*sinP;
            yb[i] = yka[i]*sinP + ykb[i]*cosP;
            gy.x += ya[i]; gy.y += yb[i];
            
            za[i] = zka[i]*cosP - zkb[i]*sinP;
            zb[i] = zka[i]*sinP + zkb[i]*cosP;
            gz.x += za[i]; gz.y += zb[i];
            
            xya[i] = xyka[i]*cosP - xykb[i]*sinP;
            xyb[i] = xyka[i]*sinP + xykb[i]*cosP;
            gxy.x += xya[i]; gxy.y += xyb[i];
            
            xza[i] = xzka[i]*cosP - xzkb[i]*sinP;
            xzb[i] = xzka[i]*sinP + xzkb[i]*cosP;
            gxz.x += xza[i]; gxz.y += xzb[i];
            
            yza[i] = yzka[i]*cosP - yzkb[i]*sinP;
            yzb[i] = yzka[i]*sinP + yzkb[i]*cosP;
            gyz.x += yza[i]; gyz.y += yzb[i];
            
            xxa[i] = xxka[i]*cosP - xxkb[i]*sinP;
            xxb[i] = xxka[i]*sinP + xxkb[i]*cosP;
            gxx.x += xxa[i]; gxx.y += xxb[i];
            
            yya[i] = yyka[i]*cosP - yykb[i]*sinP;
            yyb[i] = yyka[i]*sinP + yykb[i]*cosP;
            gyy.x += yya[i]; gyy.y += yyb[i];
            
            zza[i] = zzka[i]*cosP - zzkb[i]*sinP;
            zzb[i] = zzka[i]*sinP + zzkb[i]*cosP;
            gzz.x += zza[i]; gzz.y += zzb[i];
        }
    }
    
    public void calcGorkovGradient(Vector3f position, Vector3f forces, MainForm mf, double[] phases){
        setPosition(position);
        initFieldConstants(mf);
        updateGorkovGradient(phases);
        forces.x = (float) evalGorkovGradientX();
        forces.y = (float) evalGorkovGradientY();
        forces.z = (float) evalGorkovGradientZ();
    }
    
    public double evalGorkovGradientXProportion(){
        return  (K1*pre.dot(gx)) / (K2*( gx.dot(gxx) + gy.dot(gxy) + gz.dot(gxz)));
    }
    public double evalGorkovGradientYProportion(){
        return  (K1*pre.dot(gy)) / (K2*( gx.dot(gxy) + gy.dot(gyy) + gz.dot(gyz)));
    }
    public double evalGorkovGradientZProportion(){
        return  (K1*pre.dot(gz)) / (K2*( gx.dot(gxz) + gy.dot(gyz) + gz.dot(gzz)));
    }
    
    public double evalGorkovGradientX(){
        return  K1*pre.dot(gx) - K2*( gx.dot(gxx) + gy.dot(gxy) + gz.dot(gxz));
    }
    public double evalGorkovGradientY(){
        return  K1*pre.dot(gy) - K2*( gx.dot(gxy) + gy.dot(gyy) + gz.dot(gyz));
    }
    public double evalGorkovGradientZ(){
        return  K1*pre.dot(gz) - K2*( gx.dot(gxz) + gy.dot(gyz) + gz.dot(gzz));
    }
    public void gradientGorkovGradientX(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    pre.x*-xb[i] + -b[i]*gx.x + pre.y*xa[i] + a[i]*gx.y ) - 
                   K2 * ( 
                    gx.x*-xxb[i] + -xb[i]*gxx.x + gx.y*xxa[i] + xa[i]*gxx.y +
                    gy.x*-xyb[i] + -yb[i]*gxy.x + gy.y*xya[i] + ya[i]*gxy.y +
                    gz.x*-xzb[i] + -zb[i]*gxz.x + gz.y*xza[i] + za[i]*gxz.y);
        }
    }
    public void gradientGorkovGradientY(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    pre.x*-yb[i] + -b[i]*gy.x + pre.y*ya[i] + a[i]*gy.y ) - 
                   K2 * ( 
                    gx.x*-xyb[i] + -xb[i]*gxy.x + gx.y*xya[i] + xa[i]*gxy.y +
                    gy.x*-yyb[i] + -yb[i]*gyy.x + gy.y*yya[i] + ya[i]*gyy.y +
                    gz.x*-yzb[i] + -zb[i]*gyz.x + gz.y*yza[i] + za[i]*gyz.y);
        }
    }
    public void gradientGorkovGradientZ(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    pre.x*-zb[i] + -b[i]*gz.x + pre.y*za[i] + a[i]*gz.y ) - 
                   K2 * ( 
                    gx.x*-xzb[i] + -xb[i]*gxz.x + gx.y*xza[i] + xa[i]*gxz.y +
                    gy.x*-yzb[i] + -yb[i]*gyz.x + gy.y*yza[i] + ya[i]*gyz.y +
                    gz.x*-zzb[i] + -zb[i]*gzz.x + gz.y*zza[i] + za[i]*gzz.y);
        }
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="gorkovLaplacian">  
    public void allocateAndInit(MainForm mf){
        allocate(mf.renderer);
        initFieldConstants(mf);
    }
    
    public void allocate(Renderer r){
        a = new double[nTotalTrans]; b = new double[nTotalTrans];
        ka = new double[nTotalTrans]; kb = new double[nTotalTrans];
        
        xa = new double[nTotalTrans]; xb = new double[nTotalTrans];
        xka = new double[nTotalTrans]; xkb = new double[nTotalTrans];
        
        ya = new double[nTotalTrans]; yb = new double[nTotalTrans];
        yka = new double[nTotalTrans]; ykb = new double[nTotalTrans];
        
        za = new double[nTotalTrans]; zb = new double[nTotalTrans];
        zka = new double[nTotalTrans]; zkb = new double[nTotalTrans];
        
        xya = new double[nTotalTrans]; xyb = new double[nTotalTrans];
        xyka = new double[nTotalTrans]; xykb = new double[nTotalTrans];
        
        xza = new double[nTotalTrans]; xzb = new double[nTotalTrans];
        xzka = new double[nTotalTrans]; xzkb = new double[nTotalTrans];
        
        yza = new double[nTotalTrans]; yzb = new double[nTotalTrans];
        yzka = new double[nTotalTrans]; yzkb = new double[nTotalTrans];
        
        xxa = new double[nTotalTrans]; xxb = new double[nTotalTrans];
        xxka = new double[nTotalTrans]; xxkb = new double[nTotalTrans];
        
        yya = new double[nTotalTrans]; yyb = new double[nTotalTrans];
        yyka = new double[nTotalTrans]; yykb = new double[nTotalTrans];
        
        zza = new double[nTotalTrans]; zzb = new double[nTotalTrans];
        zzka = new double[nTotalTrans]; zzkb = new double[nTotalTrans];
        
        xxxa = new double[nTotalTrans]; xxxb = new double[nTotalTrans];
        xxxka = new double[nTotalTrans]; xxxkb = new double[nTotalTrans];
        yyya = new double[nTotalTrans]; yyyb = new double[nTotalTrans];
        yyyka = new double[nTotalTrans]; yyykb = new double[nTotalTrans];
        zzza = new double[nTotalTrans]; zzzb = new double[nTotalTrans];
        zzzka = new double[nTotalTrans]; zzzkb = new double[nTotalTrans];
        xyya = new double[nTotalTrans]; xyyb = new double[nTotalTrans];
        xyyka = new double[nTotalTrans]; xyykb = new double[nTotalTrans];
        xzza = new double[nTotalTrans]; xzzb = new double[nTotalTrans];
        xzzka = new double[nTotalTrans]; xzzkb = new double[nTotalTrans];
        yxxa = new double[nTotalTrans]; yxxb = new double[nTotalTrans];
        yxxka = new double[nTotalTrans]; yxxkb = new double[nTotalTrans];
        yzza = new double[nTotalTrans]; yzzb = new double[nTotalTrans];
        yzzka = new double[nTotalTrans]; yzzkb = new double[nTotalTrans];
        zxxa = new double[nTotalTrans]; zxxb = new double[nTotalTrans];
        zxxka = new double[nTotalTrans]; zxxkb = new double[nTotalTrans];
        zyya = new double[nTotalTrans]; zyyb = new double[nTotalTrans];
        zyyka = new double[nTotalTrans]; zyykb = new double[nTotalTrans];
    }
   
    
    public void updateGorkovLaplacian(final double[] v){
        pre.set(0);
        gx.set(0); gy.set(0); gz.set(0);
        gxx.set(0); gyy.set(0); gzz.set(0);
        gxy.set(0); gxz.set(0); gyz.set(0);
        for(int i = 0; i < nTrans; ++i){
            final double cosP = Math.cos( v[i] );
            final double sinP = Math.sin( v[i] );
            
            a[i] = ka[i]*cosP - kb[i]*sinP;
            b[i] = ka[i]*sinP + kb[i]*cosP;
            pre.x += a[i]; pre.y += b[i];
            
            xa[i] = xka[i]*cosP - xkb[i]*sinP;
            xb[i] = xka[i]*sinP + xkb[i]*cosP;
            gx.x += xa[i]; gx.y += xb[i];
            
            ya[i] = yka[i]*cosP - ykb[i]*sinP;
            yb[i] = yka[i]*sinP + ykb[i]*cosP;
            gy.x += ya[i]; gy.y += yb[i];
            
            za[i] = zka[i]*cosP - zkb[i]*sinP;
            zb[i] = zka[i]*sinP + zkb[i]*cosP;
            gz.x += za[i]; gz.y += zb[i];
            
            xya[i] = xyka[i]*cosP - xykb[i]*sinP;
            xyb[i] = xyka[i]*sinP + xykb[i]*cosP;
            gxy.x += xya[i]; gxy.y += xyb[i];
            
            xza[i] = xzka[i]*cosP - xzkb[i]*sinP;
            xzb[i] = xzka[i]*sinP + xzkb[i]*cosP;
            gxz.x += xza[i]; gxz.y += xzb[i];
            
            yza[i] = yzka[i]*cosP - yzkb[i]*sinP;
            yzb[i] = yzka[i]*sinP + yzkb[i]*cosP;
            gyz.x += yza[i]; gyz.y += yzb[i];
            
            xxa[i] = xxka[i]*cosP - xxkb[i]*sinP;
            xxb[i] = xxka[i]*sinP + xxkb[i]*cosP;
            gxx.x += xxa[i]; gxx.y += xxb[i];
            
            yya[i] = yyka[i]*cosP - yykb[i]*sinP;
            yyb[i] = yyka[i]*sinP + yykb[i]*cosP;
            gyy.x += yya[i]; gyy.y += yyb[i];
            
            zza[i] = zzka[i]*cosP - zzkb[i]*sinP;
            zzb[i] = zzka[i]*sinP + zzkb[i]*cosP;
            gzz.x += zza[i]; gzz.y += zzb[i];
            xxxa[i] = xxxka[i]*cosP - xxxkb[i]*sinP;
            
            xxxb[i] = xxxka[i]*sinP + xxxkb[i]*cosP;
            gxxx.x += xxxa[i]; gxxx.y += xxxb[i];
            yyya[i] = yyyka[i]*cosP - yyykb[i]*sinP;
            yyyb[i] = yyyka[i]*sinP + yyykb[i]*cosP;
            gyyy.x += yyya[i]; gyyy.y += yyyb[i];
            zzza[i] = zzzka[i]*cosP - zzzkb[i]*sinP;
            zzzb[i] = zzzka[i]*sinP + zzzkb[i]*cosP;
            gzzz.x += zzza[i]; gzzz.y += zzzb[i];
            xyya[i] = xyyka[i]*cosP - xyykb[i]*sinP;
            xyyb[i] = xyyka[i]*sinP + xyykb[i]*cosP;
            gxyy.x += xyya[i]; gxyy.y += xyyb[i];
            xzza[i] = xzzka[i]*cosP - xzzkb[i]*sinP;
            xzzb[i] = xzzka[i]*sinP + xzzkb[i]*cosP;
            gxzz.x += xzza[i]; gxzz.y += xzzb[i];
            yxxa[i] = yxxka[i]*cosP - yxxkb[i]*sinP;
            yxxb[i] = yxxka[i]*sinP + yxxkb[i]*cosP;
            gyxx.x += yxxa[i]; gyxx.y += yxxb[i];
            yzza[i] = yzzka[i]*cosP - yzzkb[i]*sinP;
            yzzb[i] = yzzka[i]*sinP + yzzkb[i]*cosP;
            gyzz.x += yzza[i]; gyzz.y += yzzb[i];
            zxxa[i] = zxxka[i]*cosP - zxxkb[i]*sinP;
            zxxb[i] = zxxka[i]*sinP + zxxkb[i]*cosP;
            gzxx.x += zxxa[i]; gzxx.y += zxxb[i];
            zyya[i] = zyyka[i]*cosP - zyykb[i]*sinP;
            zyyb[i] = zyyka[i]*sinP + zyykb[i]*cosP;
            gzyy.x += zyya[i]; gzyy.y += zyyb[i];

        }
    }
    
    public double evalGorkovLaplacian(){  
        return  K1 * (
                  gx.dot(gx) + pre.dot(gxx) + gy.dot(gy) + pre.dot(gyy) + gz.dot(gz) + pre.dot(gzz)) 
                - K2*
                ( gxx.dot(gxx) + gx.dot(gxxx) + gxy.dot(gxy) + gy.dot(gyxx) + gxz.dot(gxz) + gz.dot(gzxx) +
                  gxy.dot(gxy) + gx.dot(gxyy) + gyy.dot(gyy) + gy.dot(gyyy) + gyz.dot(gyz) + gz.dot(gzyy) + 
                  gxz.dot(gxz) + gx.dot(gxzz) + gyz.dot(gyz) + gy.dot(gyzz) + gzz.dot(gzz) + gz.dot(gzzz));
    }

    public double evalGorkovLaplacianX(){  
        return  K1 * (
                  gx.dot(gx) + pre.dot(gxx)) 
                - K2*
                ( gxx.dot(gxx) + gx.dot(gxxx) +
                  gxy.dot(gxy) + gx.dot(gxyy) + 
                  gxz.dot(gxz) + gx.dot(gxzz) );
    }
    public double evalGorkovLaplacianY(){  
        return  K1 * (
                  gy.dot(gy) + pre.dot(gyy)) 
                - K2*
                ( gxy.dot(gxy) + gy.dot(gyxx) +
                  gyy.dot(gyy) + gy.dot(gyyy) + 
                  gyz.dot(gyz) + gy.dot(gyzz) );
    }
    public double evalGorkovLaplacianZ(){  
        return  K1 * (
                  gz.dot(gz) + pre.dot(gzz)) 
                - K2*
                ( gxz.dot(gxz) + gz.dot(gzxx) +
                  gyz.dot(gyz) + gz.dot(gzyy) + 
                  gzz.dot(gzz) + gz.dot(gzzz));
    }
    public void gradientGorkovLaplacian(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    gx.x*-xb[i] + -xb[i]*gx.x + gx.y*xa[i] + xa[i]*gx.y +
                    pre.x*-xxb[i] + -b[i]*gxx.x + pre.y*xxa[i] + a[i]*gxx.y +
                    gy.x*-yb[i] + -yb[i]*gy.x + gy.y*ya[i] + ya[i]*gy.y +
                    pre.x*-yyb[i] + -b[i]*gyy.x + pre.y*yya[i] + a[i]*gyy.y +
                    gz.x*-zb[i] + -zb[i]*gz.x + gz.y*za[i] + za[i]*gz.y +
                    pre.x*-zzb[i] + -b[i]*gzz.x + pre.y*zza[i] + a[i]*gzz.y ) - 
                   K2 * ( 
                    gxx.x*-xxb[i] + -xxb[i]*gxx.x + gxx.y*xxa[i] + xxa[i]*gxx.y +
                    gx.x*-xxxb[i] + -xb[i]*gxxx.x + gx.y*xxxa[i] + xa[i]*gxxx.y +
                    gxy.x*-xyb[i] + -xyb[i]*gxy.x + gxy.y*xya[i] + xya[i]*gxy.y +
                    gy.x*-yxxb[i] + -yb[i]*gyxx.x + gy.y*yxxa[i] + ya[i]*gyxx.y +
                    gxz.x*-xzb[i] + -xzb[i]*gxz.x + gxz.y*xza[i] + xza[i]*gxz.y +
                    gz.x*-zxxb[i] + -zb[i]*gzxx.x + gz.y*zxxa[i] + za[i]*gzxx.y +
                    gxy.x*-xyb[i] + -xyb[i]*gxy.x + gxy.y*xya[i] + xya[i]*gxy.y +
                    gx.x*-xyyb[i] + -xb[i]*gxyy.x + gx.y*xyya[i] + xa[i]*gxyy.y +
                    gyy.x*-yyb[i] + -yyb[i]*gyy.x + gyy.y*yya[i] + yya[i]*gyy.y +
                    gy.x*-yyyb[i] + -yb[i]*gyyy.x + gy.y*yyya[i] + ya[i]*gyyy.y +
                    gyz.x*-yzb[i] + -yzb[i]*gyz.x + gyz.y*yza[i] + yza[i]*gyz.y +
                    gz.x*-zyyb[i] + -zb[i]*gzyy.x + gz.y*zyya[i] + za[i]*gzyy.y +
                    gxz.x*-xzb[i] + -xzb[i]*gxz.x + gxz.y*xza[i] + xza[i]*gxz.y +
                    gx.x*-xzzb[i] + -xb[i]*gxzz.x + gx.y*xzza[i] + xa[i]*gxzz.y +
                    gyz.x*-yzb[i] + -yzb[i]*gyz.x + gyz.y*yza[i] + yza[i]*gyz.y +
                    gy.x*-yzzb[i] + -yb[i]*gyzz.x + gy.y*yzza[i] + ya[i]*gyzz.y +
                    gzz.x*-zzb[i] + -zzb[i]*gzz.x + gzz.y*zza[i] + zza[i]*gzz.y +
                    gz.x*-zzzb[i] + -zb[i]*gzzz.x + gz.y*zzza[i] + za[i]*gzzz.y);
        }
        
        
    }
    
    public void gradientGorkovLaplacianX(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    gx.x*-xb[i] + -xb[i]*gx.x + gx.y*xa[i] + xa[i]*gx.y +
                    pre.x*-xxb[i] + -b[i]*gxx.x + pre.y*xxa[i] + a[i]*gxx.y) - 
                   K2 * ( 
                    gxx.x*-xxb[i] + -xxb[i]*gxx.x + gxx.y*xxa[i] + xxa[i]*gxx.y +
                    gx.x*-xxxb[i] + -xb[i]*gxxx.x + gx.y*xxxa[i] + xa[i]*gxxx.y +
                    gxy.x*-xyb[i] + -xyb[i]*gxy.x + gxy.y*xya[i] + xya[i]*gxy.y +
                    gx.x*-xyyb[i] + -xb[i]*gxyy.x + gx.y*xyya[i] + xa[i]*gxyy.y +
                    gxz.x*-xzb[i] + -xzb[i]*gxz.x + gxz.y*xza[i] + xza[i]*gxz.y +
                    gx.x*-xzzb[i] + -xb[i]*gxzz.x + gx.y*xzza[i] + xa[i]*gxzz.y);
        }
    }
        
    public void gradientGorkovLaplacianY(double[] g){
        for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * ( 
                    gy.x*-yb[i] + -yb[i]*gy.x + gy.y*ya[i] + ya[i]*gy.y +
                    pre.x*-yyb[i] + -b[i]*gyy.x + pre.y*yya[i] + a[i]*gyy.y ) - 
                   K2 * ( 
                    gxy.x*-xyb[i] + -xyb[i]*gxy.x + gxy.y*xya[i] + xya[i]*gxy.y +
                    gy.x*-yxxb[i] + -yb[i]*gyxx.x + gy.y*yxxa[i] + ya[i]*gyxx.y +
                    gyy.x*-yyb[i] + -yyb[i]*gyy.x + gyy.y*yya[i] + yya[i]*gyy.y +
                    gy.x*-yyyb[i] + -yb[i]*gyyy.x + gy.y*yyya[i] + ya[i]*gyyy.y +
                    gyz.x*-yzb[i] + -yzb[i]*gyz.x + gyz.y*yza[i] + yza[i]*gyz.y +
                    gy.x*-yzzb[i] + -yb[i]*gyzz.x + gy.y*yzza[i] + ya[i]*gyzz.y);
        }
        

    }
            
     public void gradientGorkovLaplacianZ(double[] g){
                for(int i = 0; i < nTrans; ++i){
            g[i] = K1 * (
                    gz.x*-zb[i] + -zb[i]*gz.x + gz.y*za[i] + za[i]*gz.y +
                    pre.x*-zzb[i] + -b[i]*gzz.x + pre.y*zza[i] + a[i]*gzz.y ) - 
                   K2 * ( 
                    gxz.x*-xzb[i] + -xzb[i]*gxz.x + gxz.y*xza[i] + xza[i]*gxz.y +
                    gz.x*-zxxb[i] + -zb[i]*gzxx.x + gz.y*zxxa[i] + za[i]*gzxx.y +
                    gyz.x*-yzb[i] + -yzb[i]*gyz.x + gyz.y*yza[i] + yza[i]*gyz.y +
                    gz.x*-zyyb[i] + -zb[i]*gzyy.x + gz.y*zyya[i] + za[i]*gzyy.y +
                    gzz.x*-zzb[i] + -zzb[i]*gzz.x + gzz.y*zza[i] + zza[i]*gzz.y +
                    gz.x*-zzzb[i] + -zb[i]*gzzz.x + gz.y*zzza[i] + za[i]*gzzz.y);
        }
    }
    
    //</editor-fold>
   
    public void reset(){
        pre.reset();
        gx.reset(); gy.reset(); gz.reset();
        gxy.reset(); gxz.reset(); gyz.reset();
        gxx.reset(); gyy.reset(); gzz.reset();
        gxxx.reset();gyyy.reset();gzzz.reset();
        gxyy.reset();gxzz.reset();
        gyxx.reset();gyzz.reset();
        gzxx.reset();gzyy.reset();
        swap.reset(); tmp.reset();
        diffVec.reset(); diffVecS.reset();
        tPos.reset();
        nor.reset();
    }
    
    public static float calcDir(float tx, float ty, float tz,final Vector3f n, float k){
        final float dot = tx*n.x + ty*n.y + tz*n.z;
        final float d2 = tx*tx + ty*ty + tz*tz;
        //final float sinAngle = FastMath.sqrt(1.0f - (dot*dot / d2) );
        final float angle = M.acos( dot / n.length() / M.sqrt(d2) );
        final float sinAngle = M.sin( angle );
        //System.out.println( "angle " + sinAngle);
        //return 1.0f - 0.25f*sinAngle - 0.6f*sinAngle*sinAngle;
        
        //return FastMath.sinc( 0.5f * k * 0.077f * sinAngle);
        
        final float dum = k * (0.009f/2.0f) * sinAngle;
        return (float)M.j1(dum) / dum;
        
        //return 1.0f / (1.0f + 0.0f*sinAngle + 128.0f*sinAngle*sinAngle);
    }
        
    public void initFieldConstantsOnlyForAmp(Renderer r){
        pre.reset();
        swap.reset(); tmp.reset();
        diffVec.reset(); diffVecS.reset();
        tPos.reset();
        nor.reset();
        
        final FloatBuffer positions = r.getPositions();
        final FloatBuffer specs = r.getSpecs();
        final FloatBuffer normals = r.getNormals();
       
        for(int i = 0; i < nTotalTrans; ++i){
            final int i3 = i*3;
            final int i4 = i*4;
            final float x,y,z;
            
            x = positions.get(i3+0); y = positions.get(i3+1); z = positions.get(i3+2);
            tPos.set(x , y , z);
            nor.set( normals.get(i3+0), normals.get(i3+1), normals.get(i3+2) );
            position.subtract(tPos, diffVec);
            float d = diffVec.length();
          
            float k = specs.get(i4 + 0);
            float kd = k*d;
            float cosKD = M.cos(kd);
            float sinKD = M.sin(kd);

            diffVecS.set(diffVec).multLocal(diffVec);
            float amp = specs.get(i4 + 1);
 
            //0 derivative
            swap.x =  cosKD;
            swap.y =  sinKD;
            swap.multLocal( amp / d );
            ka[i] = swap.x; kb[i] = swap.y;

            //directivity
            if (useDirectivity) {
                final float dir = calcDir(x, y, z, nor, k);
                ka[i] *= dir; kb[i] *= dir;
            }
                        
        }
        
        if(isReflector){
            for(int i = 0; i < nTrans; ++i){
                ka[i] +=  ka[i + nTrans]; 
                kb[i] +=  kb[i + nTrans];
            }
        }
        
    }
    
    public void initFieldConstants(final MainForm mf){
        reset();
        
        final Renderer r = mf.renderer;
        final Vector2f gorkovConsts = new Vector2f();
        
        CalcField.calcGorkovConstants(mf.scene.getParticleRadious() , mf, gorkovConsts);
        M1 = gorkovConsts.x;
        M2 = gorkovConsts.y;
        
        final FloatBuffer positions = r.getPositions();
        final FloatBuffer specs = r.getSpecs();
        final FloatBuffer normals = r.getNormals();
                
        for(int i = 0; i < nTotalTrans; ++i){
            final int i3 = i*3;
            final int i4 = i*4;
            final float x,y,z;
            
            x = positions.get(i3+0); y = positions.get(i3+1); z = positions.get(i3+2);
            tPos.set(x , y , z);
            nor.set( normals.get(i3+0), normals.get(i3+1), normals.get(i3+2) );
            position.subtract(tPos, diffVec);
            float d = diffVec.length();
            float d2 = d*d;
            float d3 = d2*d;
            float d5 = d2*d3;
            float d7 = d5*d2;
          
            float k = specs.get(i4 + 0);
            float kd = k*d;
            float k2 = k*k;
            float d2k2 = d2 * k2;
            float cosKD = M.cos(kd);
            float sinKD = M.sin(kd);
            float KDcosKD = kd * cosKD;
            float KDsinKD = kd * sinKD;

            diffVecS.set(diffVec).multLocal(diffVec);
            float amp = specs.get(i4 + 1);
 
            //0 derivative
            swap.x =  cosKD;
            swap.y =  sinKD;
            swap.multLocal( amp / d );
            ka[i] = swap.x; kb[i] = swap.y;
            
            //1 derivatives
            tmp.x = -(cosKD+KDsinKD);
            tmp.y = KDcosKD-sinKD;
            tmp.multLocal( amp / d3 );
            tmp.mult( diffVec.x, swap);
            xka[i] = swap.x; xkb[i] = swap.y;       
            tmp.mult( diffVec.y, swap);
            yka[i] = swap.x; ykb[i] = swap.y;         
            tmp.mult( diffVec.z, swap);
            zka[i] = swap.x; zkb[i] = swap.y;
                    
            //1,1 derivatives
            swap.x = 3.0f-d2k2;
            swap.y = 3.0f;
            tmp.x =  swap.x*cosKD+swap.y*KDsinKD;
            tmp.y = -(swap.y*KDcosKD-swap.x*sinKD);
            tmp.multLocal(amp / d5);
            tmp.mult( diffVec.x * diffVec.y, swap);
            xyka[i] = swap.x; xykb[i] = swap.y;         
            tmp.mult( diffVec.x * diffVec.z, swap);
            xzka[i] = swap.x; xzkb[i] = swap.y;          
            tmp.mult( diffVec.y * diffVec.z, swap);
            yzka[i] = swap.x; yzkb[i] = swap.y;
            
            //2 derivatives
            tmp.x = d2 + (d2k2 - 3.0f) * diffVecS.x;
            tmp.y = d2 - 3.0f * diffVecS.x;
            swap.x = - (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y =  tmp.y*KDcosKD-tmp.x*sinKD;
            swap.multLocal(amp / d5);
            xxka[i] = swap.x; xxkb[i] = swap.y;
                     
            tmp.x = d2 + (d2k2 - 3.0f) * diffVecS.y;
            tmp.y = d2 - 3.0f * diffVecS.y;
            swap.x = - (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y =  tmp.y*KDcosKD-tmp.x*sinKD;
            swap.multLocal(amp / d5);
            yyka[i] = swap.x; yykb[i] = swap.y;
                       
            tmp.x = d2 + (d2k2 - 3.0f) * diffVecS.z;
            tmp.y = d2 - 3.0f * diffVecS.z;
            swap.x = - (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y =  tmp.y*KDcosKD-tmp.x*sinKD;
            swap.multLocal(amp / d5);
            zzka[i] = swap.x; zzkb[i] = swap.y;
                       
            //1,2 derivatives
            swap.x = -15.0f*diffVecS.x + d2*(3.0f-k2*(d2-6.0f*diffVecS.x));
            swap.y = -15.0f*diffVecS.x + d2*(3.0f + k2*diffVecS.x);
            tmp.x = amp / d7 * (swap.x*cosKD+swap.y*KDsinKD);
            tmp.y = amp / d7 * -(swap.y*KDcosKD-swap.x*sinKD);
            yxxka[i] = tmp.x * diffVec.y; yxxkb[i] = tmp.y * diffVec.y;          
            zxxka[i] = tmp.x * diffVec.z; zxxkb[i] = tmp.y * diffVec.z;          
            swap.x = -15.0f*diffVecS.y + d2*(3.0f-k2*(d2-6.0f*diffVecS.y));
            swap.y = -15.0f*diffVecS.y + d2*(3.0f + k2*diffVecS.y);
            tmp.x = amp / d7 * (swap.x*cosKD+swap.y*KDsinKD);
            tmp.y = amp / d7 * -(swap.y*KDcosKD-swap.x*sinKD);
            xyyka[i] = tmp.x * diffVec.x; xyykb[i] = tmp.y * diffVec.x;           
            zyyka[i] = tmp.x * diffVec.z; zyykb[i] = tmp.y * diffVec.z;          
            swap.x = -15.0f*diffVecS.z + d2*(3.0f-k2*(d2-6.0f*diffVecS.z));
            swap.y = -15.0f*diffVecS.z + d2*(3.0f + k2*diffVecS.z);
            tmp.x = amp / d7 * (swap.x*cosKD+swap.y*KDsinKD);
            tmp.y = amp / d7 * -(swap.y*KDcosKD-swap.x*sinKD);
            xzzka[i] = tmp.x * diffVec.x; xzzkb[i] = tmp.y * diffVec.x;
            yzzka[i] = tmp.x * diffVec.y; yzzkb[i] = tmp.y * diffVec.y;
            
            //3 derivatives
            tmp.x = -3.0f * (5.0f *diffVecS.x + d2 * (k2*(d2 - 2.0f*diffVecS.x)-3.0f));
            tmp.y = -15.0f * diffVecS.x + d2*(9.0f +k2*diffVecS.x);
            swap.x = amp / d7 * diffVec.x * (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y = amp / d7 * diffVec.x * -(tmp.y*KDcosKD-tmp.x*sinKD);
            xxxka[i] = swap.x; xxxkb[i] = swap.y;
            
            tmp.x = -3.0f * (5.0f *diffVecS.y + d2 * (k2*(d2 - 2.0f*diffVecS.y)-3.0f));
            tmp.y = -15.0f * diffVecS.y + d2*(9.0f +k2*diffVecS.y);
            swap.x = amp / d7 * diffVec.y * (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y = amp / d7 * diffVec.y * -(tmp.y*KDcosKD-tmp.x*sinKD);
            yyyka[i] = swap.x; yyykb[i] = swap.y;
            
            tmp.x = -3.0f * (5.0f *diffVecS.z + d2 * (k2*(d2 - 2.0f*diffVecS.z)-3.0f));
            tmp.y = -15.0f * diffVecS.z + d2*(9.0f +k2*diffVecS.z);
            swap.x = amp / d7 * diffVec.z * (tmp.x*cosKD+tmp.y*KDsinKD);
            swap.y = amp / d7 * diffVec.z * -(tmp.y*KDcosKD-tmp.x*sinKD);
            zzzka[i] = swap.x; zzzkb[i] = swap.y;
            
            //directivity
            if (useDirectivity) {
                final float dir = calcDir(x, y, z, nor, k);
                final float dirX = (calcDir(x + h, y, z, nor, k) - calcDir(x - h, y, z, nor, k)) / (2.0f * h);
                final float dirY = (calcDir(x, y + h, z, nor, k) - calcDir(x, y - h, z, nor, k)) / (2.0f * h);
                final float dirZ = (calcDir(x, y, z + h, nor, k) - calcDir(x, y, z - h, nor, k)) / (2.0f * h);
                final float dirXY
                        = ((calcDir(x + h, y + h, z, nor, k) - calcDir(x - h, y + h, z, nor, k))
                        - (calcDir(x + h, y - h, z, nor, k) - calcDir(x - h, y - h, z, nor, k))) / (4.0f * h * h);
                final float dirXZ
                        = ((calcDir(x + h, y, z + h, nor, k) - calcDir(x - h, y, z + h, nor, k))
                        - (calcDir(x + h, y, z - h, nor, k) - calcDir(x - h, y, z - h, nor, k))) / (4.0f * h * h);
                final float dirYZ
                        = ((calcDir(x, y + h, z + h, nor, k) - calcDir(x, y - h, z + h, nor, k))
                        - (calcDir(x, y + h, z - h, nor, k) - calcDir(x, y - h, z - h, nor, k))) / (4.0f * h * h);
                final float dirXX
                        = (calcDir(x + h, y, z, nor, k) - 2.0f * calcDir(x, y, z, nor, k) + calcDir(x - h, y, z, nor, k))
                        / (4.0f * h * h);
                final float dirYY
                        = (calcDir(x, y + h, z, nor, k) - 2.0f * calcDir(x, y, z, nor, k) + calcDir(x, y - h, z, nor, k))
                        / (4.0f * h * h);
                final float dirZZ
                        = (calcDir(x, y, z + h, nor, k) - 2.0f * calcDir(x, y, z, nor, k) + calcDir(x, y, z - h, nor, k))
                        / (4.0f * h * h);
                final float dirYXX
                        = ((calcDir(x + h, y + h, z, nor, k) - 2.0f * calcDir(x, y + h, z, nor, k) + calcDir(x - h, y + h, z, nor, k))
                        - (calcDir(x + h, y - h, z, nor, k) - 2.0f * calcDir(x, y - h, z, nor, k) + calcDir(x - h, y - h, z, nor, k)))
                        / (8.0f * h * h * h);
                final float dirZXX
                        = ((calcDir(x + h, y, z + h, nor, k) - 2.0f * calcDir(x, y, z + h, nor, k) + calcDir(x - h, y, z + h, nor, k))
                        - (calcDir(x + h, y, z - h, nor, k) - 2.0f * calcDir(x, y, z - h, nor, k) + calcDir(x - h, y, z - h, nor, k)))
                        / (8.0f * h * h * h);
                final float dirXYY
                        = ((calcDir(x + h, y + h, z, nor, k) - 2.0f * calcDir(x + h, y, z, nor, k) + calcDir(x + h, y - h, z, nor, k))
                        - (calcDir(x - h, y + h, z, nor, k) - 2.0f * calcDir(x - h, y, z, nor, k) + calcDir(x - h, y - h, z, nor, k)))
                        / (8.0f * h * h * h);
                final float dirZYY
                        = ((calcDir(x, y + h, z + h, nor, k) - 2.0f * calcDir(x, y, z + h, nor, k) + calcDir(x, y - h, z + h, nor, k))
                        - (calcDir(x, y + h, z - h, nor, k) - 2.0f * calcDir(x, y, z - h, nor, k) + calcDir(x, y - h, z - h, nor, k)))
                        / (8.0f * h * h * h);
                final float dirXZZ
                        = ((calcDir(x + h, y, z + h, nor, k) - 2.0f * calcDir(x + h, y, z, nor, k) + calcDir(x + h, y, z - h, nor, k))
                        - (calcDir(x - h, y, z + h, nor, k) - 2.0f * calcDir(x - h, y, z, nor, k) + calcDir(x - h, y, z - h, nor, k)))
                        / (8.0f * h * h * h);
                final float dirYZZ
                        = ((calcDir(x, y + h, z + h, nor, k) - 2.0f * calcDir(x, y + h, z, nor, k) + calcDir(x, y + h, z - h, nor, k))
                        - (calcDir(x, y - h, z + h, nor, k) - 2.0f * calcDir(x, y - h, z, nor, k) + calcDir(x, y - h, z - h, nor, k)))
                        / (8.0f * h * h * h);
                final float dirXXX
                        = (calcDir(x + 2 * h, y, z, nor, k) - calcDir(x + h, y, z, nor, k)
                        + calcDir(x - h, y, z, nor, k) - calcDir(x - 2 * h, y, z, nor, k))
                        / (8.0f * h * h * h);
                final float dirYYY
                        = (calcDir(x, y + 2 * h, z, nor, k) - calcDir(x, y + h, z, nor, k)
                        + calcDir(x, y - h, z, nor, k) - calcDir(x, y - 2 * h, z, nor, k))
                        / (8.0f * h * h * h);
                final float dirZZZ
                        = (calcDir(x, y, z + 2 * h, nor, k) - calcDir(x, y, z + h, nor, k)
                        + calcDir(x, y, z - h, nor, k) - calcDir(x, y, z - 2 * h, nor, k))
                        / (8.0f * h * h * h);
                
                xxxka[i] = ka[i]*dirXXX + xxxka[i]*dir + 3*(xka[i]*dirXX + xxka[i]*dirX); 
                xxxkb[i] = kb[i]*dirXXX + xxxkb[i]*dir + 3*(xkb[i]*dirXX + xxkb[i]*dirX); 
                yyyka[i] = ka[i]*dirYYY + yyyka[i]*dir + 3*(yka[i]*dirYY + yyka[i]*dirY);
                yyykb[i] = kb[i]*dirYYY + yyykb[i]*dir + 3*(ykb[i]*dirYY + yykb[i]*dirY); 
                zzzka[i] = ka[i]*dirZZZ + xxxka[i]*dir + 3*(zka[i]*dirZZ + zzka[i]*dirZ);
                zzzkb[i] = kb[i]*dirZZZ + xxxkb[i]*dir + 3*(zkb[i]*dirZZ + zzkb[i]*dirZ); 
                
                yxxka[i] = ka[i]*dirYXX + yxxka[i]*dir + 3*(xka[i]*dirXX + xxka[i]*dirX); 
                yxxkb[i] = kb[i]*dirYXX + yxxkb[i]*dir + 3*(xkb[i]*dirXX + xxkb[i]*dirX); 
                zxxka[i] = ka[i]*dirZXX + zxxka[i]*dir + 3*(xka[i]*dirXX + xxka[i]*dirX); 
                zxxkb[i] = kb[i]*dirZXX + zxxkb[i]*dir + 3*(xkb[i]*dirXX + xxkb[i]*dirX);
                xyyka[i] = ka[i]*dirXYY + xyyka[i]*dir + 3*(yka[i]*dirYY + yyka[i]*dirY); 
                xyykb[i] = kb[i]*dirXYY + xyykb[i]*dir + 3*(ykb[i]*dirYY + yykb[i]*dirY);
                zyyka[i] = ka[i]*dirZYY + zyyka[i]*dir + 3*(yka[i]*dirYY + yyka[i]*dirY); 
                zyykb[i] = kb[i]*dirZYY + zyykb[i]*dir + 3*(ykb[i]*dirYY + yykb[i]*dirY);
                xzzka[i] = ka[i]*dirXZZ + xzzka[i]*dir + 3*(zka[i]*dirZZ + zzka[i]*dirZ); 
                xzzkb[i] = kb[i]*dirXZZ + xzzkb[i]*dir + 3*(zkb[i]*dirZZ + zzkb[i]*dirZ);
                yzzka[i] = ka[i]*dirYZZ + yzzka[i]*dir + 3*(zka[i]*dirZZ + zzka[i]*dirZ); 
                yzzkb[i] = kb[i]*dirYZZ + yzzkb[i]*dir + 3*(zkb[i]*dirZZ + zzkb[i]*dirZ);
                
                xxka[i] = ka[i]*dirXX + 2*xka[i]*dirX + xxka[i]*dir; 
                xxkb[i] = kb[i]*dirXX + 2*xkb[i]*dirX + xxkb[i]*dir;
                yyka[i] = ka[i]*dirYY + 2*yka[i]*dirY + yyka[i]*dir; 
                yykb[i] = kb[i]*dirYY + 2*ykb[i]*dirY + yykb[i]*dir;
                zzka[i] = ka[i]*dirZZ + 2*zka[i]*dirZ + zzka[i]*dir;
                zzkb[i] = kb[i]*dirZZ + 2*zkb[i]*dirZ + zzkb[i]*dir;
                xyka[i] = ka[i]*dirXY + 2*yka[i]*dirY + xyka[i]*dir; 
                xykb[i] = kb[i]*dirXY + 2*ykb[i]*dirY + xykb[i]*dir; 
                xzka[i] = ka[i]*dirXZ + 2*zka[i]*dirZ + xzka[i]*dir; 
                xzkb[i] = kb[i]*dirXZ + 2*zkb[i]*dirZ + xzkb[i]*dir;
                yzka[i] = ka[i]*dirYZ + 2*zka[i]*dirZ + yzka[i]*dir; 
                yzkb[i] = kb[i]*dirYZ + 2*zkb[i]*dirZ + yzkb[i]*dir;

                xka[i] = ka[i]*dirX + xka[i]*dir; 
                xkb[i] = kb[i]*dirX + xkb[i]*dir;
                yka[i] = ka[i]*dirY + yka[i]*dir; 
                ykb[i] = kb[i]*dirY + ykb[i]*dir;
                zka[i] = ka[i]*dirZ + zka[i]*dir; 
                zkb[i] = kb[i]*dirZ + zkb[i]*dir;
                
                ka[i] *= dir; kb[i] *= dir;
            }
                        
        }
        
        if(isReflector){
            for(int i = 0; i < nTrans; ++i){
                ka[i] +=  ka[i + nTrans]; 
                kb[i] +=  kb[i + nTrans];
                
                xka[i] +=  xka[i + nTrans]; 
                xkb[i] +=  xkb[i + nTrans];
                yka[i] +=  yka[i + nTrans]; 
                ykb[i] +=  ykb[i + nTrans];
                zka[i] +=  zka[i + nTrans]; 
                zkb[i] +=  zkb[i + nTrans];
                
                xyka[i] +=  xyka[i + nTrans]; 
                xykb[i] +=  xykb[i + nTrans];
                xzka[i] +=  xzka[i + nTrans]; 
                xzkb[i] +=  xzkb[i + nTrans];
                yzka[i] +=  yzka[i + nTrans]; 
                yzkb[i] +=  yzkb[i + nTrans];
                xxka[i] +=  xxka[i + nTrans]; 
                xxkb[i] +=  xxkb[i + nTrans];
                yyka[i] +=  yyka[i + nTrans]; 
                yykb[i] +=  yykb[i + nTrans];
                zzka[i] +=  zzka[i + nTrans]; 
                zzkb[i] +=  zzkb[i + nTrans];
                
                yxxka[i] +=  yxxka[i + nTrans]; 
                yxxkb[i] +=  yxxkb[i + nTrans];
                zxxka[i] +=  zxxka[i + nTrans]; 
                zxxkb[i] +=  zxxkb[i + nTrans];
                xyyka[i] +=  xyyka[i + nTrans]; 
                xyykb[i] +=  xyykb[i + nTrans];
                zyyka[i] +=  zyyka[i + nTrans]; 
                zyykb[i] +=  zyykb[i + nTrans];
                xzzka[i] +=  xzzka[i + nTrans]; 
                xzzkb[i] +=  xzzkb[i + nTrans];
                yzzka[i] +=  yzzka[i + nTrans]; 
                yzzkb[i] +=  yzzkb[i + nTrans];
                xxxka[i] +=  xxxka[i + nTrans]; 
                xxxkb[i] +=  xxxkb[i + nTrans];
                yyyka[i] +=  yyyka[i + nTrans]; 
                yyykb[i] +=  yyykb[i + nTrans];
                zzzka[i] +=  zzzka[i + nTrans]; 
                zzzkb[i] +=  zzzkb[i + nTrans];
            }
        }
        
        
        
        K1 = M1 * 2.0f;
        K2 = M2 * 2.0f;
    }
}