1 #include "config.h"
2 
3 /*  Copyright (C) 2002  Brad Jorsch <anomie@users.sourceforge.net>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <math.h>
21 #if TM_IN_SYS_TIME
22 # if TIME_WITH_SYS_TIME
23 #  include <sys/time.h>
24 #  include <time.h>
25 # else
26 #  if HAVE_SYS_TIME_H
27 #   include <sys/time.h>
28 #  else
29 #   include <time.h>
30 #  endif
31 # endif
32 #else
33 #include <time.h>
34 #endif
35 #include <ctype.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include "convert.h"
39 
40 /*
41  * To indicate unavailable data
42  *   999 is used for temperature
43  *   x<0 is used for rh, pressure, and windspeed
44  */
45 
46 
47 /* Calculations */
48 
rh_C(int temp_C,int dewpt_C)49 int rh_C(int temp_C, int dewpt_C){
50     float f;
51 
52     if(temp_C==999 || dewpt_C==999) return 999;
53 
54     f=1782.75*(dewpt_C-temp_C)/((237.7+dewpt_C)*(237.7+temp_C));
55     return round(pow(10, f+2));
56 }
57 
rh_F(int temp_F,int dewpt_F)58 int rh_F(int temp_F, int dewpt_F){
59     float f;
60 
61     if(temp_F==999 || dewpt_F==999) return 999;
62 
63     f=3208.95*(dewpt_F-temp_F)/((395.86+dewpt_F)*(395.86+temp_F));
64     return round(pow(10, f+2));
65 }
66 
heatindex_C(int temp_C,int rh)67 int heatindex_C(int temp_C, int rh){
68 #if 1
69     if(temp_C==999 || temp_C<21 || rh<0) return 999;
70     return heatindex_F(temp_C2F(temp_C), rh);
71 #else
72     int temp2, rh2;
73 
74     if(temp_C==999 || temp_C<38 || rh<0) return 999;
75 
76     temp2=temp_C*temp_C;
77     rh2=rh*rh;
78     return round(16.18754948 + 2.900509394*temp_C - 0.0221545692*temp2 + 4.20938791*rh - 0.26300889*temp_C*rh + 0.0039811176*temp2*rh - 0.02956469*rh2 + 0.001305828*temp_C*rh2 - 6.4476e-06*temp2*rh2);
79 #endif
80 }
81 
heatindex_F(int temp_F,int rh)82 int heatindex_F(int temp_F, int rh){
83     int temp2, temp3, rh2, rh3;
84 
85     if(temp_F==999 || temp_F<70 || rh<0) return 999;
86 
87     temp2=temp_F*temp_F;
88     temp3=temp2*temp_F;
89     rh2=rh*rh;
90     rh3=rh2*rh;
91     return round(16.923 + .185212*temp_F + 5.37941*rh - .100254*temp_F*rh + (9.41695e-3)*temp2 + (7.28898e-3)*rh2 + (3.45372e-4)*temp2*rh - (8.14971e-4)*temp_F*rh2 + (1.02102e-5)*temp2*rh2 - (3.8646e-5)*temp3 + (2.91583e-5)*rh3 + (1.42721e-6)*temp3*rh + (1.97483e-7)*temp_F*rh3 - (2.18429e-8)*temp3*rh2 + (8.43296e-10)*temp2*rh3 - (4.81975e-11)*temp3*rh3);
92 #if 0
93     return round(-42.379 + 2.04901523*temp_F + 10.14333127*rh - 0.22475541*temp_F*rh - .00683783*temp2 - .05481717*rh2 + .00122874*temp2*rh + .00085282*temp_F*rh2 - .00000199*temp2*rh2);
94 #endif
95 }
96 
windchill_C(int temp_C,int windspeed)97 int windchill_C(int temp_C, int windspeed){
98     if(temp_C==999 || windspeed<0) return 999;
99 
100     return windchill_F(temp_C2F(temp_C), windspeed);
101 }
102 
windchill_F(int temp_F,int windspeed)103 int windchill_F(int temp_F, int windspeed){
104     double ret;
105     if(temp_F==999 || windspeed<0) return 999;
106 
107     ret=35.74 + 0.6215*temp_F + (-35.75 + 0.4275*temp_F)*pow(windspeed*50292/57875.0, 0.16);
108     if(ret>temp_F) return temp_F;
109     return round(ret);
110 }
111 
112 /* Length Conversions */
113 
in2cm(int in)114 int in2cm(int in){
115     if(in<0) return in;
116     return round(in*2.54);
117 }
118 
m2mi(int meters)119 float m2mi(int meters){
120     if(meters<0) return meters;
121     return meters*125/201168;
122 }
123 
124 /* Windspeed Conversions */
125 
knots2mph(int knots)126 int knots2mph(int knots){
127     if(knots<0) return knots;
128     return round(knots*57875/50292.0);
129 }
130 
knots2kph(int knots)131 int knots2kph(int knots){
132     if(knots<0) return knots;
133     return round(knots*463/250.0);
134 }
135 
kph2knots(int kph)136 int kph2knots(int kph){
137     if(kph<0) return kph;
138     return round(kph*250/463.0);
139 }
140 
knots2mps(int knots)141 int knots2mps(int knots){
142     if(knots<0) return knots;
143     return round(knots*463/900.0);
144 }
145 
mps2knots(int mps)146 int mps2knots(int mps){
147     if(mps<0) return mps;
148     return round(mps*900/463.0);
149 }
150 
knots2beaufort(int knots)151 int knots2beaufort(int knots){
152     if(knots<0) return knots;
153     if(knots<1) return 0;
154     if(knots<=3) return 1;
155     if(knots<=6) return 2;
156     if(knots<=10) return 3;
157     if(knots<=16) return 4;
158     if(knots<=21) return 5;
159     if(knots<=27) return 6;
160     if(knots<=33) return 7;
161     if(knots<=40) return 8;
162     if(knots<=47) return 9;
163     if(knots<=55) return 10;
164     if(knots<=63) return 11;
165     return 12;
166 }
167 
168 
169 /* Temperature Conversions */
170 
temp_C2F(int temp_C)171 int temp_C2F(int temp_C){
172     if(temp_C==999) return 999;
173     return round(temp_C*9/5.0+32);
174 }
175 
temp_F2C(int temp_F)176 int temp_F2C(int temp_F){
177     if(temp_F==999) return 999;
178     return round((temp_F-32)*5/9.0);
179 }
180 
181 
182 /* Pressure Conversions */
183 
inHg2mmHg(float inHg)184 float inHg2mmHg(float inHg){
185     if(inHg<0) return inHg;
186     return inHg*25.4;
187 }
188 
inHg2hPa(float inHg)189 float inHg2hPa(float inHg){
190     if(inHg<0) return inHg;
191     return inHg*33.8639;
192 }
193 
inHg2atm(float inHg)194 float inHg2atm(float inHg){
195     if(inHg<0) return inHg;
196     return inHg*.033421052632;
197 }
198 
hPa2inHg(float hPa)199 float hPa2inHg(float hPa){
200     if(hPa<0) return hPa;
201     return hPa/33.8639;
202 }
203 
204 
205 /* Time Conversions */
206 
207 /* NOTE: y%400==100 because y=year-1900 */
208 #define is_leap(y) (y%4==0 && (y%100!=0 || y%400==100))
209 
210 /* mktime for UTC, more or less.
211  * Differences:
212  *   - no range checking
213  *   - never recalculates tm_wday or tm_yday
214  */
mkgmtime(struct tm * tm)215 time_t mkgmtime(struct tm *tm){
216     static long msec[]={0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600};
217     time_t t;
218     int i;
219 
220     while(tm->tm_mon>=12){
221         tm->tm_year++;
222         tm->tm_mon-=12;
223     }
224     while(tm->tm_mon<0){
225         tm->tm_year--;
226         tm->tm_mon+=12;
227     }
228 
229     t=0;
230     if(tm->tm_year>70){
231         for(i=70; i<tm->tm_year; i++){
232             t+=31536000;
233             if(is_leap(i)) t+=86400;
234         }
235     } else if(tm->tm_year<70){
236         for(i=69; i>=tm->tm_year; i--){
237             t-=31536000;
238             if(is_leap(i)) t-=86400;
239         }
240     }
241     t+=msec[tm->tm_mon];
242     if(tm->tm_mon>1 && is_leap(tm->tm_year)) t+=86400;
243     t+=(((tm->tm_mday-1)*24+tm->tm_hour)*60+tm->tm_min)*60+tm->tm_sec;
244 
245     return t;
246 }
247 
utc2local(int hm,int * month,int * day,int * year,int * wday)248 int utc2local(int hm, int *month, int *day, int *year, int *wday){
249     time_t t=time(NULL);
250     struct tm *tm;
251 
252     tm=gmtime(&t);
253     tm->tm_hour=hm/100;
254     tm->tm_min=hm%100;
255     if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
256     if(day!=NULL && *day!=-1) tm->tm_mday=*day;
257     if(year!=NULL && *year!=-1) tm->tm_year=*year;
258 
259     t=mkgmtime(tm);
260     tm=localtime(&t);
261 
262     if(month!=NULL) *month=tm->tm_mon+1;
263     if(day!=NULL) *day=tm->tm_mday;
264     if(year!=NULL) *year=tm->tm_year;
265     if(wday!=NULL) *wday=tm->tm_wday;
266     return tm->tm_hour*100+tm->tm_min;
267 }
268 
local2utc(int hm,int * month,int * day,int * year,int * wday)269 int local2utc(int hm, int *month, int *day, int *year, int *wday){
270     time_t t=time(NULL);
271     struct tm *tm;
272 
273     tm=localtime(&t);
274     tm->tm_hour=hm/100;
275     tm->tm_min=hm%100;
276     if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
277     if(day!=NULL && *day!=-1) tm->tm_mday=*day;
278     if(year!=NULL && *year!=-1) tm->tm_year=*year;
279 
280     t=mktime(tm);
281     tm=gmtime(&t);
282 
283     if(month!=NULL) *month=tm->tm_mon+1;
284     if(day!=NULL) *day=tm->tm_mday;
285     if(year!=NULL) *year=tm->tm_year;
286     if(wday!=NULL) *wday=tm->tm_wday;
287     return tm->tm_hour*100+tm->tm_min;
288 }
289 
fix_date(int * month,int * day,int * year,int * wday)290 void fix_date(int *month, int *day, int *year, int *wday){
291     time_t t=time(NULL);
292     struct tm *tm;
293 
294     tm=gmtime(&t);
295     if(month!=NULL && *month!=-1) tm->tm_mon=*month-1;
296     if(day!=NULL && *day!=-1) tm->tm_mday=*day;
297     if(year!=NULL && *year!=-1) tm->tm_year=*year;
298 
299     t=mkgmtime(tm);
300     tm=gmtime(&t);
301 
302     if(month!=NULL) *month=tm->tm_mon+1;
303     if(day!=NULL) *day=tm->tm_mday;
304     if(year!=NULL) *year=tm->tm_year;
305     if(wday!=NULL) *wday=tm->tm_wday;
306 }
307 
hm2min(int hm)308 int hm2min(int hm){
309     return hm/100*60+hm%100;
310 }
311 
312 /* Letter Case (destructive!) */
313 
str_upper(char * str)314 char *str_upper(char *str){
315     char *c;
316 
317     for(c=str; *c!='\0'; c++){
318         *c=toupper(*c);
319     }
320     return str;
321 }
322 
str_lower(char * str)323 char *str_lower(char *str){
324     char *c;
325 
326     for(c=str; *c!='\0'; c++){
327         *c=tolower(*c);
328     }
329     return str;
330 }
331 
332 
333 /* Angle conversions */
334 
335 /* Convert radian angle to degrees */
rad2deg(double angle)336 double rad2deg(double angle) {
337     return 180.0*angle/PI;
338 }
339 
340 /* Convert degree angle to radians */
deg2rad(double angle)341 double deg2rad(double angle) {
342     return PI*angle/180.0;
343 }
344 
345 
346 /* Date conversions */
347 
348 /*  Numerical day-of-year from month, day and year */
mdy2doy(int mn,int dy,int y)349 int mdy2doy(int mn, int dy, int y) {
350     return 275*mn/9 - ((y%4==0 && (y%100!=0 || y%400==100))?1:2)*(mn + 9)/12 + dy-30;
351 }
352 
353 /* Julian day from month/day/year */
mdy2jd(int year,int month,int day)354 double mdy2jd(int year, int month, int day) {
355     int A, B;
356 
357     year+=1900;
358     if (month <= 2) {
359         year -= 1;
360         month += 12;
361     }
362     A=year/100;
363     B=2 - A + A/4;
364 
365     return (int)(365.25*(year + 4716)) + (int)(30.6001*(month+1)) + day + B - 1524.5;
366 }
367 
368 /* convert Julian Day to centuries since J2000.0. */
jd2jcent(double jd)369 double jd2jcent(double jd) {
370     return (jd - 2451545.0)/36525.0;
371 }
372 
373 /* convert centuries since J2000.0 to Julian Day. */
jcent2jd(double t)374 double jcent2jd(double t) {
375     return t * 36525.0 + 2451545.0;
376 }
377 
378 
379 /* Lat/Long conversions */
380 
parse_dd_or_dms(char * s,char ** e)381 static double parse_dd_or_dms(char *s, char **e){
382     double deg;
383 
384     *e=s;
385     if(strchr(s, 'x') || strchr(s, 'X')) return NAN;
386     if(!strchr(s, '\'')){
387         if(!isdigit(*s) && *s!='.') return NAN;
388         return strtod(s, e);
389     }
390 
391     if(!isdigit(*s)) return NAN;
392     deg=strtol(s, e, 10);
393     if(*e==s || *e==NULL || **e!='\'') return deg;
394     s=++(*e);
395     if(!isdigit(*s)) return deg;
396     deg+=strtol(s, e, 10)/60.0;
397     if(*e==s || *e==NULL || **e!='\'') return deg;
398     s=++(*e);
399     if(!isdigit(*s) && *s!='.') return NAN;
400     deg+=strtod(s, e)/3600.0;
401     if(*e!=s && *e!=NULL && **e=='\'') (*e)++;
402     return deg;
403 }
404 
str2dd(char * s,double * lat,double * lon)405 int str2dd(char *s, double *lat, double *lon){
406     char *e;
407     int dir=0;
408     char c;
409 
410     c=toupper(*s);
411     if(c=='+' || c=='N'){
412         s++; dir=1;
413     }
414     if(c=='-' || c=='S'){
415         s++; dir=-1;
416     }
417 
418     *lat=parse_dd_or_dms(s, &e);
419     if(isnan(*lat) || e==NULL || e==s || *e=='\0') return 0;
420     if(!dir){
421         c=toupper(*e);
422         if(c=='N') dir=1;
423         if(c=='S') dir=-1;
424         if(dir) e++;
425     }
426     if(dir<0) *lat=-*lat;
427 
428     while(isspace(*e)) e++;
429     if(*e=='\0') return 0;
430 
431     s=e; dir=0;
432     c=toupper(*s);
433     if(c=='+' || c=='W'){
434         s++; dir=1;
435     }
436     if(c=='-' || c=='E'){
437         s++; dir=-1;
438     }
439 
440     *lon=parse_dd_or_dms(s, &e);
441     if(isnan(*lon) || e==s) return 0;
442     if(e==NULL || *e=='\0') return 1;
443     if(dir==0){
444         c=toupper(*e);
445         if(c=='W') dir=1;
446         if(c=='E') dir=-1;
447         if(dir!=0) e++;
448     }
449     if(dir<0) *lon=-*lon;
450 
451     return (*e=='\0');
452 }
453