module es.shape;
private import std.math;
private import es.cloneable;



real[] multiple(real[] a,real mul){
  real[] b;
  b.length = a.length;
  for(int i = a.length - 1;0 <= i;i --){
    b[i] = a[i] * mul;
  }
  return b;
}
real[][] multiple(real[][] a,real mul){
  real[][] b;
  b.length = a.length;
  for(int i = a.length - 1;0 <= i;i --){
    b[i].length = a[i].length;
    for(int j = a[i].length - 1;0 <= j;j --){
      b[i][j] = a[i][j] * mul;
    }
  }
  return b;
}

public class Shape:Cloneable{
   real[] x;
   real[] y;
   real[] z;
   public this(){
    
  }
   public this(real[] x,real[] y,real[] z){
    this.x =cast(real[])x.dup;
    this.y =cast(real[])y.dup;
    this.z =cast(real[])z.dup;
  }
   public void multi(real mul){
    x = multiple(x ,mul);
    y = multiple(y ,mul);
    z = multiple(z ,mul);
  }
   public Object clone(){
    Shape shape = new Shape(x ,y ,z);
    
    return shape;
  }
}
class Pole:Shape{
   public this(real[][] a ,real[][] b ,int segment){
    if(a.length != b.length || a.length < 1){
      assert(1);
    }
    int maxNum = 0;
    for(int i = a.length -1;0 <= i;i --){
      if(a[i].length != b[i].length || a[i].length < 1){
        assert(1);
      }
      if(maxNum < a[i].length)maxNum = a[i].length;
    }
    int k,l;
    k = 0;
    
	real[][] x0;
	real[][] y0;
	real[][] z0;
	x0.length = segment;
	y0.length = segment;
	z0.length = segment;
    for(int i = 0;i < segment ;i ++){
		x0[i].length = maxNum;
		y0[i].length = maxNum;
		z0[i].length = maxNum;
      for(int j = 0;j < maxNum ;j ++){
        if(j < a[k].length)l = j;
        else l = a[k].length - 1;
        x0[i][j] = a[k][l];
        y0[i][j] = b[k][l] * cos(cast(real)i / cast(real)segment * PI*2.0);
        z0[i][j] = b[k][l] * sin(cast(real)i / cast(real)segment * PI*2.0);
      }
      k ++;
      if(a.length <= k)k = 0;
    }
    int number = (2 * segment + 1) * maxNum;
    x = new real[number];
    y = new real[number];
    z = new real[number];
    int num = 0;
    
    for(int j = 0;j < maxNum ;j ++){
      x[num] = x0[0][j];
      y[num] = y0[0][j];
      z[num] = z0[0][j];
      num ++;
      for(int i = 0;i < segment ;i ++){
        x[num] = x0[i][j];
        y[num] = y0[i][j];
        z[num] = z0[i][j];
        num ++;
      }
      
      x[num] = x0[0][j];
      y[num] = y0[0][j];
      z[num] = z0[0][j];
      num ++;
    }
    
    int seg = 0;
    while(true){
      seg ++;
      if(segment <= seg)break; 
      for(int j = maxNum - 1;0 <= j ;j --){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
      seg ++;
      if(segment <= seg)break; 
      for(int j = 0;j < maxNum ;j ++){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
    }
    
  }
   public this(real[] a ,real[] b ,int segment){
    if(a.length != b.length || a.length < 1){
      assert(1);
    }
    real[][] x0;
	real[][] y0;
	real[][] z0;
	x0.length = segment;
	y0.length = segment;
	z0.length = segment;
    for(int i = 0;i < segment ;i ++){
		x0[i].length = a.length;
		y0[i].length = a.length;
		z0[i].length = a.length;
      for(int j = 0;j < a.length ;j ++){
        x0[i][j] = a[j];
        y0[i][j] = b[j] * cos(cast(real)i / cast(real)segment * PI * 2.0);
        z0[i][j] = b[j] * sin(cast(real)i / cast(real)segment * PI * 2.0);
      }
    }
    int number = (2 * segment + 1) * a.length;
    x.length = number;
    y.length = number;
    z.length = number;
    int num = 0;
    
    for(int j = 0;j < a.length ;j ++){
      x[num] = x0[0][j];
      y[num] = y0[0][j];
      z[num] = z0[0][j];
      num ++;
      for(int i = 0;i < segment ;i ++){
        x[num] = x0[i][j];
        y[num] = y0[i][j];
        z[num] = z0[i][j];
        num ++;
      }
      
      x[num] = x0[0][j];
      y[num] = y0[0][j];
      z[num] = z0[0][j];
      num ++;
    }
    
    int seg = 0;
    while(true){
      seg ++;
      if(segment <= seg)break; 
      for(int j = a.length - 1;0 <= j ;j --){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
      seg ++;
      if(segment <= seg)break; 
      for(int j = 0;j < a.length ;j ++){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
    }
  }
}
class Symmentry:Shape{
   public this(real[] a ,real[] b ,int segment){
    if(a.length != b.length || a.length < 1){
      assert(1);
    }
	
    real[][] x0;
    real[][] y0;
    real[][] z0;
	x0.length = segment;
	y0.length = segment;
	z0.length = segment;
    for(int i = 0;i < segment ;i ++){
		x0[i].length = a.length;
		y0[i].length = a.length;
		z0[i].length = a.length;
      for(int j = 0;j < a.length ;j ++){
        x0[i][j] = a[j];
        y0[i][j] = b[j] * cos(cast(real)i / cast(real)segment * PI * 2.0);
        z0[i][j] = b[j] * sin(cast(real)i / cast(real)segment * PI * 2.0);
      }
    }
    int number = segment * a.length;
    x = new real[number];
    y = new real[number];
    z = new real[number];
    int num = 0;
    
    int seg = 0;
    while(true){
      
      if(segment <= seg)break; 
      for(int j = a.length - 1;0 <= j ;j --){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
      seg ++;
      if(segment <= seg)break; 
      for(int j = 0;j < a.length ;j ++){
        x[num] = x0[seg][j];
        y[num] = y0[seg][j];
        z[num] = z0[seg][j];
        num ++;
      }
      seg ++;
    }
  }
}
