1
/*
2
 *=============================================================================
3
 *  naca.c generate naca airfoil profiles
4
 *
5
 *  Copyright (C) 2009  Ronald Jensen
6
 *  ron(at)jentronics.com
7
 *  http://www.jentronics.com
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 3 of the License, or
12
 *  (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program; if not, write to the Free Software
21
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 *=============================================================================
23
 */
24
25
26
#include <math.h>
27
#include <stdio.h>
28
#include <stdlib.h>
29
#include <string.h>
30
31
#include "modeler.h"
32
#include "modeler_proto.h"
33
34
void naca4digit(double m, double p, double t, struct AIRFOIL *airfoil, int stations);
35
void naca5digit(double m, double t, double K1, int q, struct AIRFOIL *airfoil, int stations);
36
double *TaperSeq(int s);
37
38
39
#ifdef STANDALONE
40
#include <unistd.h>
41
42
void Usage(char *name)
43
{
44
	fprintf(stderr, "Usage: %s [-a|r] [-n (number of points)] [-v] [-q] [-o file] NACA-X-Y-ZZZZ\n", name);
45
	fprintf(stderr, "\ta|r output in ac3d or raw format\n\tv verbose\n\tquiet\n\tn number of points in foil (at least 5)\n");
46
	fprintf(stderr, "\to filename to use instead of stdout\n");
47
	fprintf(stderr, "NACA name is in datcom format:\n The four letters NACA, a hyphen, any character, a hyphen, ");
48
	fprintf(stderr, "foil type (1, 4, 5, 6, S), a hypen, the foil number.\n");
49
}
50
51
#define OUT_RAW  0
52
#define OUT_AC3D 1
53
//#define OUT_
54
55
int verbose = 3;
56
int main(int argc, char *argv[])
57
{
58
	struct AIRFOIL airfoil;
59
	int i, count;
60
	int stations=20;
61
	int opt;
62
	int output_type=OUT_RAW;
63
	FILE *ofp=stdout;
64
65
	while ((opt = getopt(argc, argv, "ar:n:o:qv")) != -1)
66
	{
67
		switch (opt)
68
		{
69
			case 'a':
70
				output_type=OUT_AC3D;
71
				break;
72
			case 'r':
73
				output_type=OUT_RAW;
74
				break;
75
76
			case 'n':
77
				stations=atoi(optarg);
78
				if(stations<5)
79
				{
80
					Usage(argv[0]);
81
					exit(EXIT_FAILURE);
82
				}
83
				break;
84
85
			case 'o':
86
				fprintf(stderr, "Creating file: %s\n",  optarg);
87
				if( ( ofp = fopen(optarg, "w")) == NULL)
88
				{
89
					fprintf(stderr,"Unable to open %s for writing\n", optarg);
90
					exit(EXIT_FAILURE);
91
				}
92
				break;
93
			case 'v':
94
				verbose++;
95
				break;
96
			case 'q':
97
				verbose = 0;
98
				break;
99
			default: /* '?' */
100
				Usage(argv[0]);
101
				exit(EXIT_FAILURE);
102
		}
103
	}
104
105
//	fprintf(stderr, "verbose=%d; optind=%d\n", verbose, optind);
106
107
	if (optind >= argc) {
108
		Usage(argv[0]);
109
		exit(EXIT_FAILURE);
110
	}
111
	NacaFoil(argv[optind], &airfoil, stations);
112
if(output_type==OUT_AC3D) 
113
{		count=airfoil.COUNT-1;
114
	        fprintf(ofp,"AC3Db\n");
115
        	fprintf(ofp,"MATERIAL \"white\" rgb 0.788 0.788 0.788  amb 0.788 0.788 0.788  emis 0 0 0  spec 1 1 1  shi 65  trans 0\n");
116
	        fprintf(ofp,"OBJECT world\nkids %d\n", 1);
117
		fprintf(ofp,"OBJECT polyline\nname \"%s\"\ncrease 89.0\nnumvert %d\n", argv[optind], count);
118
		for(i=0;i<count;i++)
119
		{
120
			fprintf(ofp, "%0.8f 0.0 %0.8f\n", airfoil.DATAX[i], airfoil.DATAY[i]);
121
		}
122
		fprintf(ofp,"numsurf 1\nSURF 0x31\nmat 0\nrefs %d\n", count);
123
        	for(i=0;i<count;i++)
124
	        {
125
        	        fprintf(ofp, "%d 0.0 0.0\n", i);
126
	        }
127
128
		fprintf(ofp,"kids 0\n");
129
	} else {
130
		for(i=0;i<airfoil.COUNT;i++)
131
		{
132
			fprintf(ofp, "%0.8f %0.8f\n", airfoil.DATAX[i], airfoil.DATAY[i]);
133
		}
134
	}
135
	exit(EXIT_SUCCESS);
136
}
137
#else
138
extern int verbose;
139
#endif
140
141
int NacaFoil(char *name, struct AIRFOIL *foil, int stations)
142
{
143
	double m, p, t, K1;
144
	int i=16, q;
145
	char bar[3];
146
	if(strncmp("NACA", name, 4) )
147
	{
148
		return(0); //not a naca description
149
	}
150
	m = i/1000;
151
	i -= m*1000;
152
	m *= 0.01;
153
154
	p = i/100;
155
	i -= p*100;
156
	p *= 0.1;
157
158
	t = (double)i * 0.01;
159
160
	switch (name[7])
161
	{
162
	 case '1':
163
if(verbose > 1 )fprintf(stderr,"naca:%s CASE 1\n", name);
164
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, p = %0.2f, t = %0.2f\n", m, p, t);
165
	naca4digit(m, p, t, foil, stations);
166
	 break;
167
168
	 case '4':
169
if(verbose > 1 )fprintf(stderr,"naca:%s CASE 4:\n", name);
170
		bar[0] = name[9];
171
		bar[1] = 0;
172
		m = atol(bar)/100.;
173
174
		bar[0] = name[10];
175
		bar[1] = 0;
176
		p = atol(bar)/10.;
177
178
		bar[0] = name[11];
179
		bar[1] = name[12];
180
		bar[2] = 0;
181
		t = atol(bar)/100.;
182
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, p = %0.2f, t = %0.2f\n", m, p, t);
183
	naca4digit(m, p, t, foil, stations);
184
185
	 break;
186
187
	 case '5':  
188
if(verbose > 1 )fprintf(stderr,"naca:%s CASE 5:\n", name);
189
		bar[0] = name[9];
190
		bar[1] = 0;
191
		m = atol(bar)*0.15;
192
if(verbose > 2 )fprintf(stderr,"naca:  design lift coefficient = %s%% (%0.2f)\n", bar, m);
193
194
/* do thickness first so it can be set to zero if the camber position fails! */
195
		bar[0] = name[12];
196
		bar[1] = name[13];
197
		bar[2] = 0;
198
		t = atol(bar)/100.;
199
if(verbose > 2 )fprintf(stderr,"naca: thickness = %s%% (%0.2f)\n", bar, t);
200
201
202
		bar[0] = name[10];
203
		bar[1] = 0;
204
		p = atol(bar)/20.;
205
if(verbose > 2 )fprintf(stderr,"naca: max camber position = (%s/2)%% (%0.2f)\n", bar, p);
206
		switch (bar[0])
207
		{
208
			case '1':
209
				m=0.0580;
210
				K1=361.4;
211
				break;
212
			case '2':
213
				m=0.1260;
214
				K1=51.65;
215
				break;
216
			case '3':
217
				m=0.2025;
218
				K1=15.65;
219
				break;
220
			case '4':
221
				m=0.2900;
222
				K1=6.643;
223
				break;
224
			case '5':
225
				m=0.3910;
226
				K1=3.230;
227
				break;
228
			default:
229
				m=0;
230
				t=0;
231
				K1=0;
232
if(verbose > 0 )fprintf(stderr,"naca: Bad camber specification %c in %s\n", bar[0], name);
233
				break;
234
		}
235
236
		bar[0] = name[11];
237
		bar[1] = 0;
238
		q = atoi(bar);
239
if(verbose > 2 )fprintf(stderr,"naca: reflex = %s (%d)\n", bar, q);
240
241
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, K1 = %0.2f, t = %0.2f\n", m, K1, t);
242
	naca5digit(m, t, K1, q, foil, stations);
243
244
	 break;
245
246
	 case '6':
247
// NACA-V-6-631-012
248
// NACA-W-6-64210.68
249
// NACA-W-6-64-210.68
250
// 0123456789012345
251
if(verbose > 1 )fprintf(stderr,"naca: %s CASE 6\n", name);
252
		i=11;
253
		if((name[i] == '-')||(name[i] == 'A')) i++;
254
		i++;
255
		if((name[i] == '-')||(name[i] == 'A')) i+=2;
256
		bar[0]=name[i++];
257
		bar[1]=name[i];
258
		bar[2]=0;
259
		t = atol(bar)/100.;
260
if(verbose > 2 )fprintf(stderr,"naca: NACA 6 thickness = %s%% = %0.2f\n", bar, t);
261
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, p = %0.2f, t = %0.2f\n", m, p, t);
262
	naca4digit(m, p, t, foil, stations);
263
264
	 break;
265
266
	 case 'S':
267
if(verbose > 1 )fprintf(stderr,"naca:%s CASE S\n", name);
268
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, p = %0.2f, t = %0.2f\n", m, p, t);
269
	naca4digit(m, p, t, foil, stations);
270
	 break;
271
272
	 default:
273
if(verbose > 0 )fprintf(stderr,"naca: %s Unknown airfoil\n", name);
274
m=0;t=0;
275
if(verbose > 1 )fprintf(stderr,"naca: m = %0.2f, p = %0.2f, t = %0.2f\n", m, p, t);
276
	naca4digit(m, p, t, foil, stations);
277
	}
278
279
	return(1);
280
}
281
282
void naca4digit(double m, double p, double t, struct AIRFOIL *airfoil, int stations )
283
{
284
	int i, j;
285
	double yc, yt, x2, x3, x4, xroot;
286
	double Xu, Yu, Xl, Yl,dx=0, dyc=0, oyc=0, theta;
287
	double *x;
288
	x=TaperSeq(stations);
289
290
airfoil->DATAX = malloc( 2 * stations * sizeof(double) );
291
airfoil->DATAY = malloc( 2 * stations * sizeof(double) );
292
airfoil->COUNT = 2 * stations;
293
294
	for(i=0, j=2*stations-1;i<stations;i++, j--){
295
		x2 = x[i] * x[i];
296
		x3 = x2 * x[i];
297
		x4 = x3 * x[i];
298
		xroot = sqrt(x[i]);
299
		if(x[i] < p){
300
			yc = (m / (p * p)) * (2*p*x[i] - x2);
301
		} else {
302
			yc = ( m /  ((1-p)*(1-p)) ) * ( (1 -2*p)+2*p*x[i]-x2);
303
		}
304
		yt = (t/0.2)*(0.2969*xroot - 0.1260 * x[i] - 0.3516*x2 + 0.2843*x3 - 0.1015*x4);
305
		airfoil->DATAX[i] = x[i];
306
		airfoil->DATAY[i] = yc + yt;
307
		airfoil->DATAX[j] = x[i];
308
		airfoil->DATAY[j] = yc - yt;
309
	}
310
311
}
312
313
void naca5digit(double m, double t, double K1, int q, struct AIRFOIL *airfoil, int stations )
314
{
315
	int i, j;
316
	double yc, yt, x2, x3, x4, xroot, m2, m3;
317
	double Xu, Yu, Xl, Yl,dx=0, dyc=0, oyc=0, theta;
318
	double *x;
319
	x=TaperSeq(stations);
320
321
airfoil->DATAX = malloc( 2 * stations * sizeof(double) );
322
airfoil->DATAY = malloc( 2 * stations * sizeof(double) );
323
airfoil->COUNT = 2 * stations;
324
325
	for(i=0, j=2*stations-1;i<stations;i++, j--){
326
		x2 = x[i] * x[i];
327
		x3 = x2 * x[i];
328
		x4 = x3 * x[i];
329
		xroot = sqrt(x[i]);
330
		m2 = m * m;
331
		m3 = m2 * m;
332
333
		if(x[i] > m ){
334
			yc = (K1/6)*(m3*(1-(x[i])));
335
		} else {
336
			yc = (K1/6)*(x3-3*m*x2+m2*(3-m)*x[i]);
337
		}
338
339
		yt = (t/0.2)*(0.2969*xroot - 0.1260 * x[i] - 0.3516*x2 + 0.2843*x3 - 0.1015*x4);
340
		airfoil->DATAX[i] = x[i];
341
		airfoil->DATAY[i] = yc + yt;
342
		airfoil->DATAX[j] = x[i];
343
		airfoil->DATAY[j] = yc - yt;
344
	}
345
346
}
347
348
349
double *TaperSeq(int s)
350
{
351
	double k, f;
352
	int i;
353
	double *seq;
354
	seq=malloc(sizeof(double)*s);
355
356
	if(!seq) return 0;
357
358
	f=pow(2.,1./(double)(s-1));
359
	k=1.;
360
	for(i=0;i<s;i++)
361
	{
362
		seq[i]=(k-1.)*(k-1.);
363
		k *= f;
364
	}
365
	return seq;
366
}