star-cem

Compute the position of the sun
git clone git://git.meso-star.fr/star-cem.git
Log | Files | Refs | README | LICENSE

scem_main.c (4740B)


      1 /* Copyright (C) 2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redismeteobute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is dismeteobuted in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #define _XOPEN_SOURCE /* strptime support */
     17 #define _POSIX_C_SOURCE 200112L /* getopt support */
     18 
     19 #include "scem.h"
     20 
     21 #include <rsys/cstr.h>
     22 #include <rsys/mem_allocator.h>
     23 
     24 #include <stdio.h>
     25 #include <string.h>
     26 #include <time.h>
     27 #include <unistd.h> /* getopt */
     28 
     29 struct args {
     30   struct scem_location pos;
     31   struct tm time; /* In UTC+00:00 */
     32   enum scem_sun_algo algo;
     33   int radian; /* Sun position in radians instead of degrees */
     34   int verbose;
     35   int quit;
     36 };
     37 static const struct args ARGS_DEFAULT = {
     38   SCEM_LOCATION_NULL__, {0}, SCEM_SUN_MEEUS, 0, 0, 0
     39 };
     40 
     41 /*******************************************************************************
     42  * Helper functions
     43  ******************************************************************************/
     44 static INLINE void
     45 usage(FILE* stream)
     46 {
     47   fprintf(stream,
     48     "usage: scem [-hr] [-a algo] [-d utc_date] latitude longitude\n");
     49 }
     50 
     51 static res_T
     52 parse_algo(const char* str, enum scem_sun_algo* algo)
     53 {
     54   ASSERT(str && algo);
     55 
     56   if(!strcmp(str, "meeus")) {
     57     *algo = SCEM_SUN_MEEUS;
     58   } else if(!strcmp(str, "psa")) {
     59     *algo = SCEM_SUN_PSA;
     60   } else {
     61     return RES_BAD_ARG;
     62   }
     63   return RES_OK;
     64 }
     65 
     66 static res_T
     67 parse_date(const char* str, struct tm* time)
     68 {
     69   ASSERT(str && time);
     70 
     71   if(!strptime(str, "%Y-%m-%dT%H:%M:%S\n", time)) {
     72     return RES_BAD_ARG;
     73   } else {
     74     return RES_OK;
     75   }
     76 }
     77 
     78 static res_T
     79 parse_dbl
     80   (const char* str,
     81    const double min,
     82    const double max,
     83    double* out_dbl) /* In [min, max] */
     84 {
     85   double dbl = 0;
     86   res_T res = RES_OK;
     87   ASSERT(str && out_dbl && min <= max);
     88 
     89   if((res = cstr_to_double(str, &dbl)) != RES_OK) return res;
     90   if(dbl < min || dbl > max) return RES_BAD_ARG;
     91 
     92   *out_dbl = dbl;
     93   return RES_OK;
     94 }
     95 
     96 static res_T
     97 get_current_date(struct tm* date)
     98 {
     99   time_t epoch;
    100   ASSERT(date);
    101 
    102   epoch = time(NULL);
    103   if(epoch == (time_t)-1) {
    104     fprintf(stderr, "scem: error in querying local time\n");
    105     return RES_BAD_ARG;
    106   }
    107 
    108   *date = *gmtime(&epoch);
    109   return RES_OK;
    110 }
    111 
    112 static res_T
    113 args_init(struct args* args, int argc, char** argv)
    114 {
    115   int opt = 0;
    116   res_T res = RES_OK;
    117 
    118   *args = ARGS_DEFAULT;
    119 
    120   if((res = get_current_date(&args->time)) != RES_OK) goto error;
    121 
    122   while((opt = getopt(argc, argv, "a:d:hvr")) != -1) {
    123     switch(opt) {
    124       case 'a': res = parse_algo(optarg, &args->algo); break;
    125       case 'd': res = parse_date(optarg, &args->time); break;
    126       case 'h': usage(stdout); args->quit = 1; goto exit;
    127       case 'v': args->verbose = 1; break;
    128       case 'r': args->radian = 1; break;
    129       default: res = RES_BAD_ARG; break;
    130     }
    131     if(res != RES_OK) {
    132       if(optarg) {
    133         fprintf(stderr, "scem: invalid option argument '%s' -- '%c'\n",
    134           optarg, opt);
    135       }
    136       goto error;
    137     }
    138   }
    139 
    140   /* Is location missing? */
    141   if(argc - optind < 2) { res = RES_BAD_ARG; goto error; }
    142 
    143   res = parse_dbl(argv[optind+0], -90, 90, &args->pos.latitude);
    144   if(res != RES_OK) goto error;
    145   res = parse_dbl(argv[optind+1], -180, 180, &args->pos.longitude);
    146   if(res != RES_OK) goto error;
    147 exit:
    148   return res;
    149 error:
    150   usage(stderr);
    151   goto exit;
    152 }
    153 
    154 /*******************************************************************************
    155  * The program
    156  ******************************************************************************/
    157 int
    158 main(int argc, char** argv)
    159 {
    160   struct args args = ARGS_DEFAULT;
    161   struct scem_sun_pos pos = SCEM_SUN_POS_NULL;
    162   int err = 0;
    163   res_T res = RES_OK;
    164 
    165   if((res = args_init(&args, argc, argv)) != RES_OK) goto error;
    166   if(args.quit) goto exit;
    167 
    168   if(args.verbose) fprintf(stderr, "%s", asctime(&args.time));
    169 
    170   res = scem_sun_position_from_earth(&args.time, &args.pos, args.algo, &pos);
    171   if(res != RES_OK) {
    172     fprintf(stderr, "scem: error in computing the position of sun -- %s\n",
    173       res_to_cstr(res));
    174     goto error;
    175   }
    176 
    177   if(args.radian) {
    178     printf("%g %g\n", pos.zenith, pos.azimuth);
    179   } else {
    180     printf("%g %g\n", MRAD2DEG(pos.zenith), MRAD2DEG(pos.azimuth));
    181   }
    182 
    183 exit:
    184   CHK(mem_allocated_size() == 0);
    185   return err;
    186 error:
    187   err = 1;
    188   goto exit;
    189 }