Trying to use modelX() but built a spiral galaxy of points

sorry, we do have a array problem, we only see now with vertext ( and pdens = OFF )
snap-022

so again we repair the file export to cover up a array problem inside the generator

test 6(beta)
// https://discourse.processing.org/t/processing-to-draw-naca-4-digit-airfoils/5739
// http://www.airfoiltools.com/airfoil/naca4digit?MNaca4DigitForm%5Bcamber%5D=05&MNaca4DigitForm%5Bposition%5D=40&MNaca4DigitForm%5Bthick%5D=30&MNaca4DigitForm%5BnumPoints%5D=81&MNaca4DigitForm%5BcosSpace%5D=0&MNaca4DigitForm%5BcosSpace%5D=1&MNaca4DigitForm%5BcloseTe%5D=0&MNaca4DigitForm%5BcloseTe%5D=1&yt0=Plot
// http://www.pdas.com/refs/tm4741.pdf   //different calc
// https://discourse.processing.org/t/trying-to-use-modelx-but-built-a-spiral-galaxy-of-points/6064
// v02 show forum https://discourse.processing.org/t/trying-to-use-modelx-but-built-a-spiral-galaxy-of-points/6064/12
// v03 erase shear fix... and mod calc tool use "p" as x[px] with px = int(P*N)
// v04 reverse the export to file and show keyboard options on canvas
// v05b check switch point math again  // safe tuning  // show switches status
// v06(beta)  feedback, change from points to vertext shape

PShape s;

int N = 81;            //number of points
float angle;
float M = 0.00;        //  chamber//2/100.0;
float T = 0.10;        //  thickness
float P = 0.5;         // but show 5.0
float p = 0;           // can be P or x[xp] try swith key [l]
PFont font;
float[] Xvalues; 
float[] Yvalues;

// now the program starts without the file, even without the /data dir what a write could create automatic
String outfilename  = "data/new.csv";   // take out of draw and make new key [s] for save to file

boolean diag        = false;             //   if (diag) println("");
boolean recalc      = true;
float zoomit        = 300;               // airfoil norm 0 .. 1.0 for screen * 300
boolean betadens    = true;              // variable density of x[i] points or not key [i]
boolean pcalc       = false;             // key [l]
boolean showpoints  = false;             // key [q]

void setup() {
  size( 650, 300, P3D); 
  //font = loadFont("CourierNew36.vlw"); 
  font = loadFont("Verdana-Bold-48.vlw");                  // only for me kll
  println("use key [s] to save to file, key [a] print array, key [d] diag print, key [i] test x[i] pointdensity, key [l] switch p calc");
  println("use mouseWheel and key [t] for T, key [m] for M, key [p] for P");
}

void draw() {
  background(0, 0, 0);
  if ( recalc )    getOrdinates();
  show_text();
//  translate(width/2-zoomit*1.5/2.0, height/2);
  translate(width/2-zoomit/2.0, height/2);
  s = createShape();   // also need PShape s;    before setup with other global variables up top
  s.beginShape();
  s.noFill();
  s.stroke(0, 255, 255);
  s.strokeWeight(1); 
  for (int i = 0; i < 160; i++) s.vertex(zoomit*(Xvalues[i]), -zoomit*(Yvalues[i]));
  s.endShape(CLOSE);
  shape(s,0,0);
  stroke(0, 255, 0);
  strokeWeight(3);
  if (showpoints) for (int i = 0; i < 160; i++) point(zoomit*(Xvalues[i]), -zoomit*(Yvalues[i]));
}

void show_text() {
  stroke(182, 185, 188);
  strokeWeight(1);
  line( width-width, height/2, width, height/2); 
  textFont(font, 12);
  textAlign(LEFT, BOTTOM);
  String ds="(off)", ls="(off)", is="(off)";
  if (diag)      ds="(on)"; 
  if (pcalc)     ls="(on)"; 
  if (betadens)  is="(on)"; 
  text("Airfoil:\nCamber  : "+nf(M * 100.0, 1, 1) + " [m]\nThickness: "  +nf(T * 100.0, 1, 1)+" [t]\nP: "  +nf(P*10, 1, 1)+ " [p]", width/2+150, height/2+120);
  text("use: [s] save file, [a] print array, [d] diag "+ds+", [l] use Porp "+ls+", [i] pdens "+is, 10, height/2+140);
}
//_____________________________________________________________
void save_to_file() {
  Table table = new Table(); 
  String infocsv = "M="+M+",T="+T+",P="+P;    // for documentation like NACA files look
  table.addColumn("X/C");
  table.addColumn("Y/C");
  table.addColumn(infocsv);
  for (int i = 159; i > 80; i--) {
    TableRow newRow = table.addRow();
    newRow.setFloat("X/C", Xvalues[i] );
    newRow.setFloat("Y/C", Yvalues[i] );
  }  
  for (int i = 0; i < 80; i++) {
    TableRow newRow = table.addRow();
    newRow.setFloat("X/C", Xvalues[i] );
    newRow.setFloat("Y/C", Yvalues[i] );
  }
  saveTable(table, outfilename);
  println("data saved to "+outfilename);
}

//_____________________________________________________________  kll new operation
void keyPressed() {
  if ( key == 's' )  save_to_file();
  if ( key == 'q' ) {
    showpoints = !showpoints;
    println("showpoints: "+showpoints);
  }
  if ( key == 'd' ) {
    diag = !diag;
    println("diag: "+diag);
  }
  if ( key == 'i' ) {
    betadens = !betadens;
    recalc = true;
    println("betadens: "+betadens);
  }
  if ( key == 'l' ) {
    pcalc = !pcalc;
    recalc = true;
    println("pcalc: "+pcalc);
  }

  if ( key == 'a' ) {
    for (int i = 0; i < 160; i++)   println("i "+i+" array: X "+Xvalues[i]+" Y "+Yvalues[i]);
  }
}
//_____________________________________________________________
void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  if ( keyPressed && ( key == 't' || key == 'm' || key == 'p' ) ) recalc = true;
  if ( keyPressed && key == 't' )  T += 0.005*e;                // T
  if ( keyPressed && key == 'm' )  M += 0.005*e;                // M
  if ( keyPressed && key == 'p' )  P += 0.05*e;                 // P
}

//_____________________________________________________________  // rearrange local vars and alread write to globals
void getOrdinates() {  
  // acc NACA 4 digit airfoil generator (NACA 5430 AIRFOIL)
  // check input parameter bounds from tuning:
  T = constrain(T, 0.0, 1.0);
  M = constrain(M, 0.0, 1.0);
  P = constrain(P, 0.0, 1.0);

  float x[] = new float[N];
  float y[] = new float[N];
  float[] dydx = new float[N];
  //  float[] beta = new float[N];
  final float betastep = PI/(N-1);  // 80 ( not 81 ) ends with 3.14159
  int   px = 40;                // the separation left right 0 < x[px] < 1  for N(81) 0 .. 80
  final float a0 = 0.2969;
  final float a1 = -0.126;
  final float a2 = -0.3516;
  final float a3 = 0.2843;
  final float a4 = -0.1015;   // -0.1036;
  float[] theta = new float[N];
  float[] yt = new float[N];
  // by getOrdinates(); 
  float xU[] = new float[N];
  float yU[] = new float[N];
  float xL[] = new float[N];
  float yL[] = new float[N];

  for (int i = 0; i < N; i++) {                                 // need make extra loop first for that x[i] to get x[px]
    if ( betadens ) x[i] = (1 - cos(betastep * i))/2;           // 0 .. x[px] .. 1.0
    else            x[i] = i/float(N-1);
  }
  px = int(P*(N-1));                                            // new idea , they want change "p" ?split position? depending on P [0 .. 1.0]
  if (pcalc) p= x[px];
  else       p = P;                                             // both not ok as we use the cos(beta) point density
  if (diag)   println(" P "+P+" x["+px+"] "+nf(p, 1, 3));
  // v05
  float ppp = p*p;
  float tailadd = 0;
  for (int i = 0; i < N; i++) {
    if (i > px) {                                               // with this we change the calculation
      ppp = (1-p)*(1-p);
      tailadd = (1 - 2.0*P);
    }
    y[i]    = M * (tailadd + 2.0 * P * x[i] - x[i]*x[i])/ppp;
    dydx[i] = 2.0 * M * (P - x[i])/ppp;
  }

  for (int i = 0; i < N; i++) {
    yt[i] = T*( a0*sqrt(x[i])+ a1*x[i] + a2*x[i]*x[i] + a3*x[i]*x[i]*x[i] + a4*x[i]*x[i]*x[i]*x[i] )/0.2;
    theta[i] = atan(dydx[i]);        // atan gives -PI/2 to PI/2 
    if (diag) println("i "+i+" dydx[i] "+nf(dydx[i], 1, 3)+" theta[i] " +nf(theta[i], 1, 3)+" yt[i] "+nf(yt[i], 1, 3));
    xU[i] = x[i] - yt[i]  * sin(theta[i]); 
    yU[i] = y[i] + yt[i]  * cos(theta[i]);
    xL[i] = x[i] + yt[i]  * sin(theta[i]);        
    yL[i] = y[i] - yt[i]  * cos(theta[i]);
  }

  Xvalues = concat(xU, xL);               // return: set the globals with the results
  Yvalues = concat(yU, yL);

  recalc = false;
}
//_______________________________

That looks familiar. angle is not used now but that was why I calculated it. If you apply a shearY(angle) to the bottom Y’s it will close that up. That’s an extreme case there though unless building a blimp.

actually i think it is just the sequence of points in the array
as points all ok,
as vertex connects point to point with a line ( as you not use curveVertex )
you make that wrong list order visible

if we fix the loops, array concat and vertex and original export will work.

now it looks so easy ha?

Xvalues = concat(reverse(xU), xL);
Yvalues = concat(reverse(yU), yL);

but i see some small data problems,
if there is a rule like all X data must be between 0.0 … 1.0
it is violated by that calculation i have now,
like for one x i see -4.7982467E-4
not sure i can / must put in a constrain??
a test looks not good.

now for the vertex, as the array sort is clean now, also the CLOSE works
correct ( there is no vertex line from x = 0 to x = 1 any more )

test v07b
// https://discourse.processing.org/t/processing-to-draw-naca-4-digit-airfoils/5739
// http://www.airfoiltools.com/airfoil/naca4digit?MNaca4DigitForm%5Bcamber%5D=05&MNaca4DigitForm%5Bposition%5D=40&MNaca4DigitForm%5Bthick%5D=30&MNaca4DigitForm%5BnumPoints%5D=81&MNaca4DigitForm%5BcosSpace%5D=0&MNaca4DigitForm%5BcosSpace%5D=1&MNaca4DigitForm%5BcloseTe%5D=0&MNaca4DigitForm%5BcloseTe%5D=1&yt0=Plot
// http://www.pdas.com/refs/tm4741.pdf   //different calc
// https://discourse.processing.org/t/trying-to-use-modelx-but-built-a-spiral-galaxy-of-points/6064
// v02 show forum https://discourse.processing.org/t/trying-to-use-modelx-but-built-a-spiral-galaxy-of-points/6064/12
// v03 erase shear fix... and mod calc tool use "p" as x[px] with px = int(P*N)
// v04 reverse the export to file and show keyboard options on canvas
// v05b check switch point math again  // safe tuning  // show switches status
// v06(beta)  feedback, change from points to vertext shape
// v06        new array sort, back with export array, key [h], limit test ( x < 0 )  not look good
// v07        https://discourse.processing.org/t/trying-to-use-modelx-but-built-a-spiral-galaxy-of-points/6064/24?u=kll
//            new calc code check
// v07b       show P as 0 .. 1 

PShape s;

int N = 100;           // number of points
int cdata = 200;       // number of records 
float angle;
float M = 0.00;        // chamber//2/100.0;
float T = 0.10;        // thickness
float P = 0.5;         // but show 5.0
float p = 0;           // can be P or x[xp] try swith key [l]
PFont font;
float[] Xvalues; 
float[] Yvalues;

// now the program starts without the file, even without the /data dir what a write could create automatic
String outfilename  = "data/new.csv";   // take out of draw and make new key [s] for save to file

boolean diag        = false;             //   if (diag) println("");
boolean recalc      = true;
float zoomit        = 300;               // airfoil norm 0 .. 1.0 for screen * 300
boolean betadens    = true;              // variable density of x[i] points or not key [i]
boolean showpoints  = false;             // key [q]
boolean showtext    = true;              // key [h]
String mytitle = "AIRFOIL v0.7b";

void setup() {
  size( 650, 300, P3D);
  surface.setTitle(mytitle);
  font = loadFont("CourierNew36.vlw"); 
  println("use key [s] to save to file, key [a] print array, key [d] diag print,");
  println("key [i] pointdensity, key [q] show points, key [h] showtext");
  println("use mouseWheel and key [t] for T, key [m] for M, key [p] for P");
}

void draw() {
  background(0, 0, 0);
  if ( recalc )    getOrdinates();
  if (showtext)    show_text();
  //  translate(width/2-zoomit*1.5/2.0, height/2);
  translate(width/2-zoomit/2.0, height/2);
  s = createShape();   // also need PShape s;    before setup with other global variables up top
  s.beginShape();
  s.noFill();
  s.stroke(0, 255, 255);
  s.strokeWeight(1); 
  for (int i = 0; i < cdata; i++) s.vertex(zoomit*(Xvalues[i]), -zoomit*(Yvalues[i]));
  s.endShape(CLOSE);
  shape(s, 0, 0);
  stroke(0, 255, 0);
  strokeWeight(3);
  if (showpoints) for (int i = 0; i < cdata; i++) point(zoomit*(Xvalues[i]), -zoomit*(Yvalues[i]));
}

void show_text() {
  stroke(182, 185, 188);
  strokeWeight(1);
  line( width-width, height/2, width, height/2); 
  textFont(font, 14);
  textAlign(LEFT, BOTTOM);
  String ds="(off)", is="(off)", qs="(off)";
  if (diag)        ds="(on)"; 
  if (betadens)    is="(on)"; 
  if (showpoints)  qs="(on)"; 
  text("Airfoil:\nCamber  : "+nf(M * 100.0, 1, 1) + " [m]\nThickness: "  +nf(T * 100.0, 1, 1)+" [t]\nHighpoint(P): "  +nf(P, 1, 2)+ " [p]", width/2+120, height/2+100);
  text("use: [s] save file, [a] print array, [d] diag "+ds, 10, height/2+120);
  text(" [i] pdens "+is+", [q] points "+qs+", [h] disable this text", 10, height/2+140);
}
//_____________________________________________________________
void save_to_file() {
  Table table = new Table(); 
  String infocsv = "_M="+M+"_T="+T+"_P="+P;    // for documentation like NACA info
  table.addColumn("X/C");
  table.addColumn("Y/C");
  table.addColumn(infocsv);
  for (int i = 0; i < cdata; i++) {             // v06 change back to normal export
    TableRow newRow = table.addRow();
    newRow.setFloat("X/C", Xvalues[i] );
    newRow.setFloat("Y/C", Yvalues[i] );
  }
  saveTable(table, outfilename);
  println("data saved to "+outfilename);
}

//_____________________________________________________________  kll new operation
void keyPressed() {
  if ( key == 'i' || key == 'l' )   recalc = true;
  if ( key == 'h' )  showtext = !showtext;
  if ( key == 's' )  save_to_file();
  if ( key == 'q' )  showpoints = !showpoints;
  if ( key == 'd' )  diag = !diag;
  if ( key == 'i' )  betadens = !betadens;
  if ( key == 'a' ) for (int i = 0; i < cdata; i++)   println("i "+i+" array: X "+Xvalues[i]+" Y "+Yvalues[i]);
}
//_____________________________________________________________
void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  if ( keyPressed && ( key == 't' || key == 'm' || key == 'p' ) ) recalc = true;
  if ( keyPressed && key == 't' )  T += 0.002*e;                // T
  if ( keyPressed && key == 'm' )  M += 0.002*e;                // M
  if ( keyPressed && key == 'p' )  P += 0.02*e;                 // P
}

//_____________________________________________________________  // rearrange local vars and alread write to globals
void getOrdinates() {  
  // acc NACA 4 digit airfoil generator (NACA 5430 AIRFOIL)
  // check input parameter bounds from tuning:
  T = constrain(T, 0.0, 1.0);
  M = constrain(M, 0.0, 1.0);
  P = constrain(P, 0.0, 1.0);
  if (diag) println(" T "+T+" M "+M+" P "+P);
  float x[] = new float[N];
  float y[] = new float[N];
  float[] dydx = new float[N];
  //  float[] beta = new float[N];
  final float betastep = PI/N;
  final float a0 = 0.2969;
  final float a1 = -0.126;
  final float a2 = -0.3516;
  final float a3 = 0.2843;
  final float a4 = -0.1015;   // -0.1036;
  float[] theta = new float[N];
  float[] yt = new float[N];
  // by getOrdinates(); 
  float xU[] = new float[N];
  float yU[] = new float[N];
  float xL[] = new float[N];
  float yL[] = new float[N];

  for (int i = 0; i < N; i++) {
    if ( betadens ) x[i] = (1 - cos(betastep * i))/2;           // 0 .. x[P] .. 1.0
    else            x[i] = i/float(N);
    float ppp = P*P;
    float tailadd = 0;
    if (x[i] > P) {                                             // v07 now correct jump
      ppp = (1-P)*(1-P);
      tailadd = (1 - 2.0*P);
    }
    y[i]    = M * (tailadd + 2.0 * P * x[i] - x[i]*x[i])/ppp;
    dydx[i] = 2.0 * M * (P - x[i])/ppp;
  }

  for (int i = 0; i < N; i++) {
    yt[i] = T*( a0*sqrt(x[i])+ a1*x[i] + a2*x[i]*x[i] + a3*x[i]*x[i]*x[i] + a4*x[i]*x[i]*x[i]*x[i] )/0.2;
    theta[i] = atan(dydx[i]);        // atan gives -PI/2 to PI/2 
    //if (diag) println("i "+i+" dydx[i] "+nf(dydx[i], 1, 3)+" theta[i] " +nf(theta[i], 1, 3)+" yt[i] "+nf(yt[i], 1, 3));
    xU[i] = x[i] - yt[i]  * sin(theta[i]); 
    yU[i] = y[i] + yt[i]  * cos(theta[i]);
    xL[i] = x[i] + yt[i]  * sin(theta[i]); 
    yL[i] = y[i] - yt[i]  * cos(theta[i]);
  }
  Xvalues = concat(reverse(xU), xL);               // return: set the globals with the results
  Yvalues = concat(reverse(yU), yL);
  recalc = false;
}
//_______________________________

An expert aerodynamicist pointed out some problems and fixes with my code. I think you @kll might have incorporated some of my bugs. I was using radians incorrectly, was missing a set of parenthesis, and had misplaced a0. Here is my corrected getOrdinates() function:

void getOrdinates(){
   
  for (int i = 0; i < N; i++){
  
    M = zoom/2500f;
    T = tzoom/2500f;
   
    beta[i] = (radians(180)/100.0) * i;
    x[i] = (1 - cos(beta[i]))/2;
    
    if(x[i] < P) {
      
     y[i] = ((M/(P*P) * (2*P*x[i] - x[i]*x[i])));
     dydx[i] = (2*M)/(P*P) * (P - x[i]);
   
     } else{ 
    
    y[i] = (M/((1-P)*(1-P))) * (1 - 2*P + 2*P*x[i] - x[i]*x[i]); 
    dydx[i] = (2*M/((1-P)*(1-P)) * (P - x[i])); 
//     } 
   }    
}  //end for loop

   for (int i = 0; i < N; i++){
   
       yt[i] = (T/0.2* (a0* sqrt(x[i])+ a1*x[i] + a2*(x[i]*x[i]) + a3*(x[i]*x[i]*x[i]) + a4*(x[i]*x[i]*x[i]*x[i])));
       theta[i] = (atan((dydx[i])));
       xU[i] = x[i] - yt[i] * (sin((theta[i]))); 
       yU[i] = ( (y[i] + yt[i]  * (cos((theta[i]))) ) );
       xL[i] = x[i] + yt[i] * sin((theta[i]));        
       yL[i] = (y[i] - yt[i] * cos((theta[i]))); 
      
}

   
    }

Smoothed

good, not sure how many i already found,

  • as you checked, the points out of my version are ok,
    so for me it is just the program flow about the P position.
    ( and the visualization)

here i have a question, i got the same foil
but on screen i print P 2.0
you show 0.2
can you check on the definition and the *100
also i am confused about the new

    M = zoom/2500f;
    T = tzoom/2500f;

in your old

    M = zoom/1000f;
    T = tzoom/1000f;

i not use it as i erased the sliders,
but worry i have a 2.5 error now???

  • the ( ((( ))))))) is very difficult to read.

  • by the way your post tells me that you never checked
    on my “repair”

  • so you changed from 81 to 100?
    ( file 200 lines )?
    as i only see the calc part i can not know how long are your arrays and loops now.
    snap-025

No, sorry about jumping all around between what I’ve done and your improvements. I like my sliders and I like your keyboard and mousewheel inputs. I am using one mousewheel input for P and will use a key ‘s’ for saving the file. I’ll post it soon and will try your latest version and look at the differences.

The P = 0.2 vs. 2.0? I don’t know yet, I just print the P as is. It is a percentage of the chord length. I’ll be back later.

but here i see:

P is the position of the maximum camber divided by 10. In the example P=4 so the maximum camber is at 0.4 or 40% of the chord.

but up to you, 7b show 0.xx