Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

rhsfun_examples.c

Go to the documentation of this file.
00001 /***********************************************************
00002 
00003   file:  rhsfun_examples.c
00004 
00005 These RHS functions are used in the Quake-Soar agent.  They
00006 are modified versions of the routines taken from TacAir-Soar.
00007 *************************************************************/
00008 
00009 #include "soarkernel.h"
00010 #include <math.h>
00011 #include <time.h>
00012 #include <ctype.h>
00013 #include <string.h>
00014 
00015 #include "rhsfun.h"
00016 #include "rhsfun_examples.h"
00017 
00018 /* M_PI sometimes isn't picked up from math.h */
00019 #ifndef M_PI
00020 #define M_PI 3.14159265358979323846
00021 #endif
00022 
00023 /* "Normalizes" an integral heading to be between -180 and +180 */
00024 long normalize_heading_int(long n)
00025 {
00026     /* we need to make sure that -180 < value <= 180 so we modify */
00027     /*  the original rounded value using the fact that for heading, */
00028     /*  for any integer value of x, the following holds:            */
00029     /*            heading1 = x*360 + heading2                      */
00030     while (n <= -180)
00031         n += 360;
00032     while (n > 180)
00033         n -= 360;
00034 
00035     return n;
00036 }
00037 
00038 /* "Normalizes" a floating point heading to be between -180.0 and +180.0 */
00039 float normalize_heading_float(float n)
00040 {
00041     /* we need to make sure that -180 < value <= 180 so we modify */
00042     /*  the original rounded value using the fact that for heading, */
00043     /*  for any integer value of x, the following holds:            */
00044     /*            heading1 = x*360 + heading2                      */
00045     while (n <= -180.0)
00046         n += 360.0;
00047     while (n > 180.0)
00048         n -= 360.0;
00049 
00050     return n;
00051 }
00052 
00053 long round_off_heading_int(long n, long m)
00054 {
00055     long unbounded_rounded;
00056 
00057     /* need to round the first (i_n) to the nearest second (i_m) */
00058     if (n < 0)
00059         unbounded_rounded = m * (long) ((n - (long) (m / 2)) / m);
00060     else
00061         unbounded_rounded = m * (long) ((n + (long) (m / 2)) / m);
00062 
00063     return unbounded_rounded;
00064 }
00065 
00066 float round_off_heading_float(float n, float m)
00067 {
00068     float n_10, m_10, unbounded_rounded;
00069     double ip;
00070     double ip2;
00071 
00072     /* OK.  Both n and m can have tenths, so multiply by 10 and treat
00073        as integers */
00074     modf((n * 10.0), &ip);
00075     n_10 = (float) ip;
00076     modf((m * 10.0), &ip);
00077     m_10 = (float) ip;
00078 
00079     if (n_10 < 0.0) {
00080 
00081         modf((m_10 / 2.0), &ip2);
00082         modf(((n_10 - ip2) / m_10), &ip);
00083         unbounded_rounded = (float) (m_10 * ip);
00084     } else {
00085 
00086         modf((m_10 / 2.0), &ip2);
00087         modf(((n_10 + ip2) / m_10), &ip);
00088         unbounded_rounded = (float) (m_10 * ip);
00089     }
00090 
00091     /* Divide by 10 to get tenths back and return */
00092     return (float) (unbounded_rounded / 10.0);
00093 }
00094 
00095 Symbol *round_off_heading_air_rhs_function_code(list * args)
00096 {
00097     Symbol *arg;
00098     float n = 0, f_m = 0;
00099     long i_m = 0;
00100     cons *c;
00101     bool float_found = FALSE;
00102 
00103     if (!args) {
00104         print("Error: 'round_off_heading' function called with no arguments\n");
00105         return NIL;
00106     }
00107 
00108     if (!args->rest) {
00109         /* --- only one argument --- */
00110         print("Error: 'round_off_heading' function called with only one argument.\n");
00111         return NIL;
00112     }
00113 
00114     /* --- two or more arguments --- */
00115     arg = args->first;
00116     if (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE)
00117         n = (float) arg->ic.value;
00118     else if (arg->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
00119         n = arg->fc.value;
00120     }
00121 
00122     c = args->rest;
00123     if (c->rest) {
00124         /* --- more than two arguments --- */
00125         print("Error: 'round_off_heading' function called with more than two arguments.\n");
00126         return NIL;
00127     }
00128     arg = c->first;
00129     if (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE)
00130         i_m = (long) arg->ic.value;
00131     else if (arg->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
00132         float_found = TRUE;
00133         f_m = arg->fc.value;
00134     }
00135 
00136     /* Now, deal with the arguments based on type and return result */
00137     if (float_found)
00138         return make_float_constant(normalize_heading_float(round_off_heading_float(n, f_m)));
00139     else
00140         return make_int_constant(normalize_heading_int(round_off_heading_int((long) n, i_m)));
00141 
00142 }
00143 
00144 /* code for round_off_heading */
00145 
00146 /* --------------------------------------------------------------------
00147                                 round_off
00148 
00149  Takes two numbers and returns the first rounded to the nearest second.
00150 -------------------------------------------------------------------- */
00151 Symbol *round_off_air_rhs_function_code(list * args)
00152 {
00153     Symbol *arg;
00154     float n = 0, f_m = 0;
00155     long i_m = 0;
00156     cons *c;
00157     bool float_found = FALSE;
00158 
00159     if (!args) {
00160         print("Error: 'round_off' function called with no arguments\n");
00161         return NIL;
00162     }
00163 
00164     if (!args->rest) {
00165         /* --- only one argument --- */
00166         print("Error: 'round_off' function called with only one argument.\n");
00167         return NIL;
00168     }
00169 
00170     /* --- two or more arguments --- */
00171     arg = args->first;
00172     if (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE)
00173         n = (float) arg->ic.value;
00174     else if (arg->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
00175         n = arg->fc.value;
00176     }
00177 
00178     c = args->rest;
00179     if (c->rest) {
00180         /* --- more than two arguments --- */
00181         print("Error: 'round_off' function called with more than two arguments.\n");
00182         return NIL;
00183     }
00184     arg = c->first;
00185     if (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE)
00186         i_m = arg->ic.value;
00187     else if (arg->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE) {
00188         float_found = TRUE;
00189         f_m = arg->fc.value;
00190     }
00191 
00192     /* Now, deal with the arguments based on type and return result */
00193     if (float_found)
00194         return make_float_constant(round_off_heading_float(n, f_m));
00195     else
00196         return make_int_constant(round_off_heading_int((long) n, i_m));
00197 }
00198 
00199 typedef double float64;
00200 #define PI 3.141592653589
00201 #define PI_OVER_TWO (PI/2)
00202 #define TWO_PI (PI*2)
00203 #define RAD_TO_DEG(X) ((X*180)/PI)
00204 #define X 0
00205 #define Y 1
00206 #define Z 2
00207 
00208 void vector_from_to_position(float64 pos1[3], float64 pos2[3], float64 vector[3])
00209 {
00210     vector[X] = pos2[X] - pos1[X];
00211     vector[Y] = pos2[Y] - pos1[Y];
00212     vector[Z] = pos2[Z] - pos1[Z];
00213 }
00214 
00215 void vec2_norm(float64 v[3], float64 r[3], int abort)
00216 {
00217     float64 mag, mag2;
00218     mag2 = v[X] * v[X] + v[Y] * v[Y];
00219     mag = sqrt(mag2);
00220     if (!abort && (mag < 0.01)) {
00221         r[0] = 1.0;
00222         r[1] = 0.0;
00223         return;
00224     }
00225     r[0] = v[0] / mag;
00226     r[1] = v[1] / mag;
00227 }
00228 
00229 float64 convert_to_soar_angle(float64 heading_in_rads)
00230 {
00231     double heading;
00232 
00233     /* Not only correct, but more efficient! */
00234     heading = heading_in_rads - PI_OVER_TWO;
00235     if (heading < 0.0)
00236         heading += TWO_PI;
00237     heading = TWO_PI - heading;
00238     if (heading > PI)
00239         heading -= TWO_PI;
00240 
00241     return heading;
00242 }
00243 
00244 void hrl_xydof_to_heading(float64 xydof[3], float64 * output)
00245 {
00246     float64 heading_in_rads;
00247 
00248     heading_in_rads = convert_to_soar_angle(atan2(xydof[Y], xydof[X]));
00249 
00250     (*output) = heading_in_rads;
00251 }
00252 
00253 long air_soar_round_off_angle(long n, long m)
00254 {
00255     long unbounded_rounded, bounded_rounded;
00256 
00257     /* need to round the first (n) to the nearest second (m) */
00258     if (n < 0)
00259         unbounded_rounded = m * (long) ((n - (long) (m / 2)) / m);
00260     else
00261         unbounded_rounded = m * (long) ((n + (long) (m / 2)) / m);
00262 
00263     /* we need to make sure that -180 < value <= 180. */
00264 
00265     bounded_rounded = (unbounded_rounded % 360);
00266     if (bounded_rounded > 180)
00267         bounded_rounded -= 360;
00268     if (bounded_rounded <= -180)
00269         bounded_rounded += 360;
00270 
00271     return bounded_rounded;
00272 }
00273 
00274 float64 bracket_rad_to_deg(float64 var)
00275 {
00276     return (float64) air_soar_round_off_angle((long) RAD_TO_DEG(var), 1);
00277 }
00278 
00279 long convert(float64 flo)
00280 {
00281     long tempx;
00282     tempx = (long) flo;
00283     return tempx;
00284 }
00285 
00286 long heading_to_point(long current_x, long current_y, long x, long y)
00287 {
00288     float64 plane_pos[3], waypoint_pos[3], dir[3];
00289     float64 heading;
00290 
00291     plane_pos[0] = (float64) current_x;
00292     plane_pos[1] = (float64) current_y;
00293     plane_pos[2] = 0;
00294 
00295     waypoint_pos[0] = (float64) x;
00296     waypoint_pos[1] = (float64) y;
00297     waypoint_pos[2] = 0;
00298 
00299     vector_from_to_position(plane_pos, waypoint_pos, dir);
00300     vec2_norm(dir, dir, FALSE);
00301     hrl_xydof_to_heading(dir, &heading);
00302 
00303     return convert(bracket_rad_to_deg(heading));
00304 }
00305 
00306 /* --------------------------------------------------------------------
00307                                 compute-heading
00308 
00309  Takes 4 args and returns integer heading from x1,y1 to x2,y2
00310 -------------------------------------------------------------------- */
00311 
00312 Symbol *compute_heading_rhs_function_code(list * args)
00313 {
00314     Symbol *arg;
00315     long current_x, current_y;
00316     long waypoint_x, waypoint_y;
00317     int count;
00318     cons *c;
00319 
00320     if (!args) {
00321         print("Error: 'compute-heading' function called with no arguments\n");
00322         return NIL;
00323     }
00324 
00325     for (c = args; c != NIL; c = c->rest) {
00326         arg = c->first;
00327         if ((arg->common.symbol_type != INT_CONSTANT_SYMBOL_TYPE) &&
00328             (arg->common.symbol_type != FLOAT_CONSTANT_SYMBOL_TYPE)) {
00329             print_with_symbols("Error: non-number (%y) passed to - compute-heading\n", arg);
00330             return NIL;
00331         }
00332     }
00333 
00334     count = 1;
00335 
00336     for (c = args->rest; c != NIL; c = c->rest) {
00337         arg = c->first;
00338         if ((arg->common.symbol_type != INT_CONSTANT_SYMBOL_TYPE) &&
00339             (arg->common.symbol_type != FLOAT_CONSTANT_SYMBOL_TYPE)) {
00340             print_with_symbols("Error: non-number (%y) passed to compute-heading function.\n", arg);
00341             return NIL;
00342         } else {
00343             count++;
00344         }
00345     }
00346 
00347     if (count != 4) {
00348         print("Error: 'compute-heading' takes exactly 4 arguments.\n");
00349         return NIL;
00350     }
00351 
00352     arg = args->first;
00353     current_x = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? arg->ic.value : (long) arg->fc.value;
00354 
00355     arg = args->rest->first;
00356     current_y = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? arg->ic.value : (long) arg->fc.value;
00357 
00358     arg = args->rest->rest->first;
00359     waypoint_x = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? arg->ic.value : (long) arg->fc.value;
00360 
00361     arg = args->rest->rest->rest->first;
00362     waypoint_y = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? arg->ic.value : (long) arg->fc.value;
00363 
00364     return make_int_constant(heading_to_point(current_x, current_y, waypoint_x, waypoint_y));
00365 }
00366 
00367 /* --------------------------------------------------------------------
00368                                 compute-range
00369 
00370  Takes 4 args and returns integer range from x1,y1 to x2,y2
00371 -------------------------------------------------------------------- */
00372 
00373 Symbol *compute_range_rhs_function_code(list * args)
00374 {
00375     Symbol *arg;
00376     double current_x, current_y;
00377     double waypoint_x, waypoint_y;
00378     int count;
00379     cons *c;
00380 
00381     if (!args) {
00382         print("Error: 'compute-range' function called with no arguments\n");
00383         return NIL;
00384     }
00385 
00386     for (c = args; c != NIL; c = c->rest) {
00387         arg = c->first;
00388         if ((arg->common.symbol_type != INT_CONSTANT_SYMBOL_TYPE)
00389             && (arg->common.symbol_type != FLOAT_CONSTANT_SYMBOL_TYPE)) {
00390             print_with_symbols("Error: non-number (%y) passed to - compute-range\n", arg);
00391             return NIL;
00392         }
00393     }
00394 
00395     count = 1;
00396 
00397     for (c = args->rest; c != NIL; c = c->rest) {
00398         arg = c->first;
00399         if ((arg->common.symbol_type != INT_CONSTANT_SYMBOL_TYPE)
00400             && (arg->common.symbol_type != FLOAT_CONSTANT_SYMBOL_TYPE)) {
00401             print_with_symbols("Error: non-number (%y) passed to compute-range function.\n", arg);
00402             return NIL;
00403         } else {
00404             count++;
00405         }
00406     }
00407 
00408     if (count != 4) {
00409         print("Error: 'compute-range' takes exactly 4 arguments.\n");
00410         return NIL;
00411     }
00412 
00413     arg = args->first;
00414     current_x = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? (double) arg->ic.value : arg->fc.value;
00415 
00416     arg = args->rest->first;
00417     current_y = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? (double) arg->ic.value : arg->fc.value;
00418 
00419     arg = args->rest->rest->first;
00420     waypoint_x = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? (double) arg->ic.value : arg->fc.value;
00421 
00422     arg = args->rest->rest->rest->first;
00423     waypoint_y = (arg->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE) ? (double) arg->ic.value : arg->fc.value;
00424 
00425     return make_int_constant((long int) sqrt((current_x - waypoint_x)
00426                                              * (current_x - waypoint_x)
00427                                              + (current_y - waypoint_y)
00428                                              * (current_y - waypoint_y)));
00429 }
00430 
00431 /*****************************************************************************/
00432 
00433 void add_bot_rhs_functions()
00434 {
00435     add_rhs_function(make_sym_constant("round-off-heading"), round_off_heading_air_rhs_function_code, 2, TRUE, FALSE);
00436     add_rhs_function(make_sym_constant("round-off"), round_off_air_rhs_function_code, 2, TRUE, FALSE);
00437 
00438     add_rhs_function(make_sym_constant("compute-heading"), compute_heading_rhs_function_code, 4, TRUE, FALSE);
00439 
00440     add_rhs_function(make_sym_constant("compute-range"), compute_range_rhs_function_code, 4, TRUE, FALSE);
00441 }
00442 
00443 void remove_bot_rhs_functions()
00444 {
00445     remove_rhs_function(make_sym_constant("round-off-heading"));
00446     remove_rhs_function(make_sym_constant("round-off"));
00447     remove_rhs_function(make_sym_constant("compute-heading"));
00448     remove_rhs_function(make_sym_constant("compute-range"));
00449 }

Generated on Thu Dec 11 13:00:20 2003 for Soar Kernel by doxygen 1.3.5