import sk.uniba.fmph.pocprak.simplegraphics.*;
/**
 * Trieda reprezentujuca elektrostaticke pole v rovine xy. Bodove naboje vytvarajuce pole su tiez v rovine xy
 */
public class poleE {
  /**
   * Hodnota (kladna) elementarneho naboja v Coulomboch
   */
  public static final double elnaboj = 1.602E-19;//elementarny naboj
  /**
   * Velkost nanometra vyjadrena v metroch
   */
  public static final double nm =1.E-9; //nanometer
  /**
   * Perimitivita vakua v SI jednotkach F/m
   */
  public static final double epsilon=8.854E-12;//permitivita vakua

  /**
   * Do tohto pola (array) treba ulozit bodove naboje vytvarajuce pole
   */
  public naboj qs[];

  /**
   * default constructor, prazdne pole
   */
  public poleE(){
    //pole nabojov inicializuje na pole nulovej dlzky
    qs = new naboj[0];
  }

  /**
   * Constructor, vytvori elektricke pole budene nabojmi, ulozenymi v array q
   */
  public poleE(naboj[] q){
    qs = q;
  }


  /**
   * Vrati vektor intenzity elektrickeho pola v bode R v jednotkach V/nm
   */
  public vector E(point R){
    vector E=new vector(0.,0.);
    if(qs.length==0) return E;
    for(int i=0;i<qs.length;i++){
      E = vector.plus(E,Coulomb(R,qs[i]));
    }
    E = vector.times(nm,E);  // prevod na jednotky V/nm
    return E;
  }

  /** Vypocita pracu vykonanu jednodtkovym nabojom pozdlz zadanej cesty
   *  vysledok vrati vo Voltoch. Cesta je zadana nejakym poctom bodov.
   *  Predpoklada sa ze medzi dvoma bodmi cesty uz netreba pri vypocte integralu interpolovat,
   *  teda ze pole je na useku cesty medzi jej dvoma urcujucimi bodmi konstantné
   */

  public double praca(Path pth){
    double sum=0;
    for (int i = 0; i<pth.n-1; i++){
      vector deltar = new vector(pth.p[i+1],pth.p[i]); //toto je maly vektor z jedneho bodu cesty do dalsieho
      vector E = this.E(pth.p[i]); //toto je elektricke pole na tom mieste cesty
      // upravte teraz nasledujuci riadok aby sa sumovalo co sa ma sumovat pre vypocet
      //prace. Navod, trieda vector ma metodu double scalarproduct(vector v1, vector v2)
      sum = sum+0.;
    }
    return sum;
  }

  /**
  * Vrati potencial elektrickeho pola v bode R v jednotkach V
  */
  public double phi(point R){
    double phi = 0;
    if(qs.length==0) return phi;
    for(int i=0;i<qs.length;i++){
      phi = phi+CoulombPotential(R,qs[i]);
    }
    return phi;
  }

  /**
   * Nakresli silociaru startujuc na obe strany z bodu R
   */
  public void silociara(point R, GrGraphics gr){
    double dksi = 0.0001; //krok
    point p = R;  //polozi aktualny bod silociary do startovacieho bodu R
    for(int i=0;i<150;i++){//15000 bodov silociary rozdelencyh do dvoch cyklov,
      for(int j=0;j<100;j++){ //aby sa kreslilo po vacsich usekoch
        vector direction = E(p).unit(); //jednotkovy vektor v smere intenzity pola v bode p
        double xnew = p.x + dksi * direction.x;
        double ynew = p.y + dksi * direction.y;
        p = new point(xnew, ynew);
        p.draw(gr);
      }
      gr.repaint();
    }
    //teraz to iste na opacnu stranu, proti smeru pola
    p = R;
    for(int i=0;i<150;i++){
      for(int j=0;j<100;j++){
        vector direction = E(p).unit(); //jednotkovy vektor v smere poila v bode p
        double xnew = p.x - dksi * direction.x;
        double ynew = p.y - dksi * direction.y;
        p = new point(xnew, ynew);
        p.draw(gr);
      }
      gr.repaint();
    }

  }


  /**
   * Nakresli ekvipotencialnu ciaru startujuc na obe strany z bodu R
   */
  public void ekvipotciara(point R, GrGraphics gr){
    double dksi = 0.0001;
    point p = R;
    for(int i=0;i<200;i++){
      for(int j=0;j<100;j++){
        vector intensity = E(p); //Elektricke pole v bode p
        vector ekvidirection = intensity.perpendicular();
        double xnew = p.x + dksi * ekvidirection.x;
        double ynew = p.y + dksi * ekvidirection.y;
        p = new point(xnew, ynew);
        p.draw(gr);
      }
      gr.repaint();
    }
    //teraz to iste na opacnu stranu, proti smeru pola
    p = R;
    for(int i=0;i<200;i++){
      for(int j=0;j<100;j++){
        vector intensity = E(p); //Elektricke pole v bode p
        vector ekvidirection = intensity.perpendicular();
        double xnew = p.x - dksi * ekvidirection.x;
        double ynew = p.y - dksi * ekvidirection.y;
        p = new point(xnew, ynew);
        p.draw(gr);
      }
      gr.repaint();
    }

  }


  /**
   * Vypocita vektor intenzity pola v mieste (R.x,R.y), ktore je
   * budene nabojom Q. Poloha objektu naboj Q je (Q.x,Q.y)
   */
  public static vector Coulomb(point R, naboj Q){
    //napred vypocitame jednotkovy vektor smerujuci od naboja k bodu R, kde sa pocita pole
    vector dir = vector.direction(R,Q);
    //teraz vyupocitame vzdialenost od bodu Q k bodu R
    double r = point.distance(R,Q)*nm; //suradnice su v nm, my to potrebujeme v m
    if(r==0)r=Double.MIN_VALUE; //trochu surova korekcia neziaducej chyby
    double tmp = Q.q*elnaboj; //naboj vyjadreny v Coulomboch

    tmp = tmp/(4.*Math.PI*epsilon*r*r); //velkost pola aj so znamienkom naboja
    //teraz touto hodnotou vynasobime jednotkovy vektor
    //!!!!!!!!!!!ibaze v nasledujucum riadku sme to nenaprogramovali dobre, opravte ho
    return vector.times(1,dir);
  }

  public static double CoulombPotential(point R, naboj Q){
    //teraz vyupocitame vzdialenost od bodu Q k bodu R
    double r = point.distance(R,Q)*nm; //suradnice su v nm, my to potrebujeme v m
    if(r==0)r=Double.MIN_VALUE;
    double tmp = Q.q*elnaboj; //naboj vyjadreny v Coulomboch
    tmp = tmp/(4.*Math.PI*epsilon*r);
    return tmp;
  }



}
