Projet
This commit is contained in:
987
projet/src/map.c
Normal file
987
projet/src/map.c
Normal file
@@ -0,0 +1,987 @@
|
||||
#include "map.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mymath.h"
|
||||
#include "cutils.h"
|
||||
|
||||
map_t *map;
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* Geometry
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
/** Euclidian distance betwen two points (xa,ya) and (xb,yb) */
|
||||
float distance(float xa, float ya, float xb, float yb)
|
||||
{
|
||||
/* use of math.h function */
|
||||
return hypotf(xa - xb, ya - yb);
|
||||
}
|
||||
|
||||
/** Convert angle from radian to degree */
|
||||
float todegree(float a)
|
||||
{
|
||||
return (a * 180.0) / M_PI;
|
||||
}
|
||||
|
||||
/** Convert angle from degree to radian */
|
||||
float toradian(float a)
|
||||
{
|
||||
return (a * M_PI) / 180.0;
|
||||
}
|
||||
|
||||
/** Get the cadran of the angle (in degree) */
|
||||
int tocadran(float a) {
|
||||
if ((0 <= a && a < 90) ||
|
||||
(-360 <= a && a < -270))
|
||||
return 1;
|
||||
if ((90 <= a && a < 180) ||
|
||||
(-270 <= a && a < -180))
|
||||
return 2;
|
||||
if ((180 <= a && a < 270) ||
|
||||
(-180 <= a && a < -90))
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
/** Angle (in degree) of a segment */
|
||||
float lineAngle(float x1, float y1, float x2, float y2)
|
||||
{
|
||||
/* use of math.h function for arctan */
|
||||
return todegree(atan2(y2-y1,x2-x1));
|
||||
}
|
||||
|
||||
/** Angle inside an arc delimited by (from,to) */
|
||||
bool isInArc(float a, float from, float to)
|
||||
{
|
||||
if (from < to) {
|
||||
// trigo direction
|
||||
return (from <= a && a <= to) || (from <= (a+360) && (a+360) <= to);
|
||||
}
|
||||
else {
|
||||
// clock direction
|
||||
return (to <= a && a <= from) || (to <= (a+360) && (a+360) <= from);
|
||||
}
|
||||
}
|
||||
|
||||
/** Angles in ordred inside an arc delimited by (from,to) */
|
||||
bool fourAnglesInOrder(float from,float x,float y, float to)
|
||||
{
|
||||
if (from < to) {
|
||||
// trigo direction
|
||||
return
|
||||
(from<=x && x<=y && y<=to) ||
|
||||
(from<=x+360 && x+360<=y+360 && y+360<=to) ||
|
||||
(from<=x && x<=y+360 && y+360<=to) ||
|
||||
(from<=x+360 && x+360<=y && y<=to);
|
||||
} else {
|
||||
// clock direction
|
||||
return (to <= y && y<=x && x <= from) ||
|
||||
(to <= y+360 && y+360<=x+360 && x+360 <= from) ||
|
||||
(to <= y+360 && y+360<=x && x <= from) ||
|
||||
(to <= y && y<=x+360 && x+360 <= from);
|
||||
}
|
||||
}
|
||||
|
||||
/** Product of two vectors for directions */
|
||||
float dirProd(float dir1x, float dir1y, float dir2x, float dir2y)
|
||||
{
|
||||
return dir1x * dir2x + dir1y * dir2y;
|
||||
}
|
||||
|
||||
float dirVProd(float dir1x, float dir1y, float dir2x, float dir2y)
|
||||
{
|
||||
return dir1x * dir2y - dir1y * dir2x;
|
||||
}
|
||||
|
||||
/** Size of a direction vector */
|
||||
float dirNorm(float dir1x, float dir1y)
|
||||
{
|
||||
/* use of math.h function */
|
||||
return hypot(dir1x, dir1y);
|
||||
}
|
||||
|
||||
/** Cos of directions */
|
||||
float dirCos(float dir1x, float dir1y, float dir2x, float dir2y)
|
||||
{
|
||||
return dirProd(dir1x, dir1y, dir2x, dir2y)
|
||||
/ (dirNorm(dir1x, dir1y) * dirNorm(dir2x, dir2y));
|
||||
}
|
||||
|
||||
/** Project point (x,y) on line d(p1,p2) and
|
||||
* return result on (px, py)
|
||||
*/
|
||||
void
|
||||
dirProjPoint( /* IN */ float x, float y, position_t * p1, position_t * p2,
|
||||
/* OUT */ float *px, float *py)
|
||||
{
|
||||
//compute direction vector for d(p1, p2)
|
||||
float dir_x = p2->x - p1->x;
|
||||
float dir_y = p2->y - p1->y;
|
||||
float dirn = dirNorm(dir_x, dir_y);
|
||||
|
||||
//compute P1 - H
|
||||
float p1h = ((x - p1->x) * dir_x + (y - p1->y) * dir_y) / dirn;
|
||||
|
||||
//compute h
|
||||
(*px) = p1->x + (p1h * dir_x) / dirn;
|
||||
(*py) = p1->y + (p1h * dir_y) / dirn;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* =========================================================================
|
||||
* Parsing
|
||||
* =========================================================================
|
||||
*/
|
||||
|
||||
typedef void (*map_segment_line_loader)(FILE *, /* file to read */
|
||||
const char *, /* file name */
|
||||
void *, /* pointer to the element
|
||||
to be filled */
|
||||
size_t); /* line number */
|
||||
|
||||
void map_load_segment(FILE *f,
|
||||
const char *filename,
|
||||
map_segment_line_loader loader,
|
||||
const char *segment_name,
|
||||
void *psegment,
|
||||
int *segment_size,
|
||||
size_t element_size,
|
||||
size_t segment_max_size,
|
||||
size_t *pline) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (segment_name);
|
||||
assert (psegment);
|
||||
assert (segment_size);
|
||||
assert (pline);
|
||||
|
||||
char kword[15], **segment = (char **)psegment;
|
||||
int rcode;
|
||||
|
||||
/* read until "segment_name" encountered */
|
||||
while (true) {
|
||||
rcode = fscanf(f, "%14s", kword);
|
||||
(*pline)++;
|
||||
|
||||
if ((rcode == EOF) || (strcmp(kword, "end") == 0))
|
||||
log_fatal("[map %s] could not find segment %s\n", filename, segment_name);
|
||||
|
||||
if (strcmp(kword, segment_name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* "segment_name" has been read, now read item number */
|
||||
rcode = fscanf(f, "%d", segment_size);
|
||||
if (rcode == EOF)
|
||||
log_fatal("[map %s] reached end of file while looking"
|
||||
" for element count in segment %s (line %zu)\n",
|
||||
filename, segment_name, *pline);
|
||||
if ((*segment_size < 0) || (*segment_size > segment_max_size))
|
||||
log_fatal("[map %s] too many (%d) elements in "
|
||||
"segment %s (should be <= %d) (line %zu)\n",
|
||||
filename, *segment_size, segment_name, segment_max_size, *pline);
|
||||
(*pline)++;
|
||||
|
||||
/* allocate enough elements */
|
||||
*segment = calloc(*segment_size, element_size);
|
||||
assert(*segment);
|
||||
|
||||
log_info("[map %s] starting to read segment %s of size %zu\n",
|
||||
filename, segment_name, *segment_size);
|
||||
for (size_t i = 0; i < *segment_size; i++, (*pline)++)
|
||||
loader(f, filename, &(*segment)[i * element_size], *pline);
|
||||
log_info("[map %s] finished reading segment %s\n", filename, segment_name);
|
||||
}
|
||||
|
||||
void rd_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
char kword[15];
|
||||
road_t *rd = (road_t *)p;
|
||||
int rcode = fscanf(f, "%14s", kword);
|
||||
|
||||
if (rcode == EOF)
|
||||
log_fatal("[map %s] 'line|arc' expected (line %zu)\n", filename, line);
|
||||
|
||||
if (strcmp(kword, "line") == 0) {
|
||||
int nbdir = 0;
|
||||
/* read "line <dir> <max_speed> <startX> <startY> <endX> <endY>" */
|
||||
rcode = fscanf(f, "%d %d %f %f %f %f",
|
||||
&nbdir, &rd->max_speed,
|
||||
&rd->u.line.startp.x, &rd->u.line.startp.y,
|
||||
&rd->u.line.endp.x, &rd->u.line.endp.y);
|
||||
if ((rcode == EOF) ||
|
||||
(nbdir < 1) ||
|
||||
(nbdir > 2) ||
|
||||
(rd->max_speed <= 0) ||
|
||||
(rd->max_speed >= SPEED_MAX) ||
|
||||
(rd->u.line.startp.x <= MIN_X) ||
|
||||
(rd->u.line.startp.x >= MAX_X) ||
|
||||
(rd->u.line.endp.x <= MIN_X) ||
|
||||
(rd->u.line.endp.x >= MAX_X) ||
|
||||
(rd->u.line.startp.y <= MIN_Y) ||
|
||||
(rd->u.line.startp.y >= MAX_Y) ||
|
||||
(rd->u.line.endp.y <= MIN_Y) ||
|
||||
(rd->u.line.endp.y >= MAX_Y))
|
||||
log_fatal("[map_read %s]: 'line' format error (line %zu)\n",
|
||||
filename, line);
|
||||
|
||||
rd->color = COL_ROADLINE;
|
||||
rd->kind = (nbdir == 1) ? RD_LINE_1 : RD_LINE_2;
|
||||
rd->dir_x = (rd->u.line.endp.x - rd->u.line.startp.x);
|
||||
rd->dir_y = (rd->u.line.endp.y - rd->u.line.startp.y);
|
||||
} else if (strcmp(kword, "arc") == 0) {
|
||||
int nbdir = 0;
|
||||
/* read "arc <dir> <max_speed> <centerX> <centerY>
|
||||
<radius> <start_angle> <end_angle>" */
|
||||
rcode = fscanf(f, "%d %d %f %f %f %f %f",
|
||||
&nbdir, &rd->max_speed,
|
||||
&rd->u.arc.center.x, &rd->u.arc.center.y,
|
||||
&rd->u.arc.radius,
|
||||
&rd->u.arc.start_angle,
|
||||
&rd->u.arc.end_angle);
|
||||
if ((rcode == EOF) ||
|
||||
(nbdir != 1) ||
|
||||
(rd->max_speed <= 0) ||
|
||||
(rd->max_speed >= SPEED_MAX) ||
|
||||
(rd->u.arc.center.x <= MIN_X) ||
|
||||
(rd->u.arc.center.x >= MAX_X) ||
|
||||
(rd->u.arc.center.y <= MIN_Y) ||
|
||||
(rd->u.arc.center.y >= MAX_Y) ||
|
||||
(rd->u.arc.radius <= 0) ||
|
||||
(rd->u.arc.start_angle < -180.0) ||
|
||||
(rd->u.arc.start_angle >= 360.0) ||
|
||||
(rd->u.arc.end_angle < -180.0) ||
|
||||
(rd->u.arc.end_angle >= 360.0))
|
||||
log_fatal("[map %s]: 'arc' format error (line %zu)\n",
|
||||
filename, line);
|
||||
rd->color = COL_ROADLINE;
|
||||
rd->kind = RD_ARC;
|
||||
rd->dir_x = 0.0;
|
||||
rd->dir_y = (rd->u.arc.start_angle < rd->u.arc.end_angle) ? -1.0 : 1.0;
|
||||
} else {
|
||||
log_fatal("[map %s] unknown road type %s (line %zu)\n",
|
||||
filename, kword, line);
|
||||
}
|
||||
}
|
||||
|
||||
void wayp_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
int rcode;
|
||||
waypoint_t *wp = (waypoint_t *)p;
|
||||
|
||||
/* read <road> <X> <Y> */
|
||||
rcode = fscanf(f, "%d %f %f", &wp->road, &wp->position.x, &wp->position.y);
|
||||
if ((rcode == EOF) ||
|
||||
(wp->road < 0) ||
|
||||
(wp->road >= map->road_sz) ||
|
||||
(wp->position.x <= MIN_X) ||
|
||||
(wp->position.x >= MAX_X) ||
|
||||
(wp->position.y <= MIN_Y) ||
|
||||
(wp->position.y >= MAX_Y)) {
|
||||
log_fatal("[map %s] waypoint format error (line %zu)\n", filename, line);
|
||||
}
|
||||
}
|
||||
|
||||
void tl_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
int rcode;
|
||||
tlight_t *tl = (tlight_t *)p;
|
||||
|
||||
/* read <road> <X> <Y> <delayR> <delayA> <delayG> <dephase> */
|
||||
rcode = fscanf(f, "%d %f %f %d %d %d %d",
|
||||
&tl->road,
|
||||
&tl->tl.ptl_pos.x, &tl->tl.ptl_pos.y,
|
||||
&tl->tl.ptl_red, &tl->tl.ptl_amber, &tl->tl.ptl_green,
|
||||
&tl->tl.ptl_phase);
|
||||
if ((rcode == EOF) ||
|
||||
(tl->road < 0) ||
|
||||
(tl->road >= map->road_sz) ||
|
||||
(tl->tl.ptl_pos.x <= MIN_X) ||
|
||||
(tl->tl.ptl_pos.x >= MAX_X) ||
|
||||
(tl->tl.ptl_pos.y <= MIN_Y) ||
|
||||
(tl->tl.ptl_pos.y >= MAX_Y))
|
||||
log_fatal("[map %s] traffic light format error (line %zu)\n",
|
||||
filename, line);
|
||||
}
|
||||
|
||||
void st_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
int rcode;
|
||||
stop_t *st = (stop_t *)p;
|
||||
|
||||
/* read <road> <tlight> <X> <Y> */
|
||||
rcode = fscanf(f, "%d %d %f %f",
|
||||
&st->road, &st->sema,
|
||||
&st->position.x, &st->position.y);
|
||||
if ((rcode == EOF) ||
|
||||
(st->road < 0) ||
|
||||
(st->road >= map->road_sz) ||
|
||||
(st->sema < 0) ||
|
||||
(st->sema >= map->tlight_sz) ||
|
||||
(st->position.x <= MIN_X) ||
|
||||
(st->position.x >= MAX_X) ||
|
||||
(st->position.y <= MIN_Y) ||
|
||||
(st->position.y >= MAX_Y))
|
||||
log_fatal("[map %s] stop format error (line %zu)\n", filename, line);
|
||||
}
|
||||
|
||||
void obst_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
int rcode;
|
||||
obst_t *obst = (obst_t *)p;
|
||||
|
||||
rcode = fscanf(f, "%f %f %f %f", &obst->pot_pos.x, &obst->pot_pos.y,
|
||||
&obst->pot_since, &obst->pot_till);
|
||||
if ((rcode == EOF) ||
|
||||
(obst->pot_pos.x <= MIN_X) ||
|
||||
(obst->pot_pos.x >= MAX_X) ||
|
||||
(obst->pot_pos.y <= MIN_Y) ||
|
||||
(obst->pot_pos.y >= MAX_Y))
|
||||
log_fatal("[map %s] obstacle format error (line %zu)\n", filename, line);
|
||||
}
|
||||
|
||||
void iti_segment_line_loader(FILE *f,
|
||||
const char *filename,
|
||||
void *p,
|
||||
size_t line) {
|
||||
assert (f);
|
||||
assert (filename);
|
||||
assert (p);
|
||||
|
||||
char kword[15];
|
||||
iti_t *iti = (iti_t *)p;
|
||||
int rcode = fscanf(f, "%14s %f", kword, &iti->param);
|
||||
|
||||
if (strcmp(kword, "go") == 0) {
|
||||
iti->act = Globals__Go;
|
||||
if ((rcode == EOF) || (iti->param <= 0.f) || (iti->param > SPEED_MAX))
|
||||
log_fatal("[map %s] itinerary format error (action Go, line %zu)\n",
|
||||
filename, line);
|
||||
} else if (strcmp(kword, "turn") == 0) {
|
||||
iti->act = Globals__Turn;
|
||||
if ((rcode == EOF) || (iti->param < -180.0) || (iti->param >= 360.0))
|
||||
log_fatal("[map %s] itinerary format error (action Turn, line %zu)\n",
|
||||
filename, line);
|
||||
} else if (strcmp(kword, "stop") == 0) {
|
||||
iti->act = Globals__Stop;
|
||||
iti->param = 0.f; /* Dummy */
|
||||
} else {
|
||||
log_fatal("[map %s] itinerary format error (unknown action %s, line %zu)\n",
|
||||
filename, kword, line);
|
||||
}
|
||||
}
|
||||
|
||||
void map_read_string_line(FILE *f, const char *filename,
|
||||
const char *expected_kw, char *buff, size_t *pline) {
|
||||
char kword[15];
|
||||
int rcode = fscanf(f, "%14s %249s", kword, buff);
|
||||
if ((rcode == EOF) || (strcmp(kword, expected_kw) != 0))
|
||||
log_fatal("[map %s] could not read %s (line %zu)\n",
|
||||
filename, expected_kw, *pline);
|
||||
if (buff[0] != '"' || buff[strlen(buff) - 1] != '"')
|
||||
log_fatal("[map %s] string after %s should be between double quotes"
|
||||
" (line %zu)\n",
|
||||
filename, expected_kw, *pline);
|
||||
(*pline)++;
|
||||
|
||||
/* Remove surrounding double quotes. */
|
||||
memmove(buff, buff + 1, strlen(buff) - 2);
|
||||
buff[strlen(buff) - 2] = 0;
|
||||
|
||||
log_info("[map %s] read %s: %s\n", filename, expected_kw, buff);
|
||||
}
|
||||
|
||||
void map_load(const char *filename) {
|
||||
map = malloc(sizeof *map);
|
||||
assert(map);
|
||||
bzero(map, sizeof *map);
|
||||
|
||||
size_t line = 1;
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (!f)
|
||||
log_fatal("[map %s] could not open file\n", filename);
|
||||
|
||||
map_read_string_line(f, filename, "map", map->name, &line);
|
||||
map_read_string_line(f, filename, "graphics", map->graphics, &line);
|
||||
map_read_string_line(f, filename, "guide", map->guide, &line);
|
||||
|
||||
char kword[15];
|
||||
int rcode = fscanf(f, "%14s %f %f %f", kword,
|
||||
&map->init_phase.ph_pos.x,
|
||||
&map->init_phase.ph_pos.y,
|
||||
&map->init_phase.ph_head);
|
||||
if ((rcode == EOF) || (strcmp(kword, "init") != 0))
|
||||
log_fatal("[map %s] could not read init (line %zu)\n", filename, line);
|
||||
line++;
|
||||
log_info("[map %s] read init: x = %f, y = %f, head = %f\n",
|
||||
filename,
|
||||
map->init_phase.ph_pos.x,
|
||||
map->init_phase.ph_pos.y,
|
||||
map->init_phase.ph_head);
|
||||
|
||||
/* Read the roads. */
|
||||
map_load_segment(f, filename, rd_segment_line_loader, "rd",
|
||||
&map->road_arr, &map->road_sz, sizeof *map->road_arr,
|
||||
MAX_ROAD_COUNT, &line);
|
||||
|
||||
/* Read the waypoints. */
|
||||
map_load_segment(f, filename, wayp_segment_line_loader, "wp",
|
||||
&map->wayp_arr, &map->wayp_sz, sizeof *map->wayp_arr,
|
||||
MAX_WAYP_COUNT, &line);
|
||||
|
||||
/* Read the traffic lights. */
|
||||
map_load_segment(f, filename, tl_segment_line_loader, "tl",
|
||||
&map->tlight_arr, &map->tlight_sz, sizeof *map->tlight_arr,
|
||||
MAX_TL_COUNT, &line);
|
||||
|
||||
/* Read the stops. */
|
||||
map_load_segment(f, filename, st_segment_line_loader, "st",
|
||||
&map->stop_arr, &map->stop_sz, sizeof *map->stop_arr,
|
||||
MAX_STOP_COUNT, &line);
|
||||
|
||||
/* Read the obstacles. */
|
||||
map_load_segment(f, filename, obst_segment_line_loader, "obst",
|
||||
&map->obst_arr, &map->obst_sz, sizeof *map->obst_arr,
|
||||
MAX_OBST_COUNT, &line);
|
||||
|
||||
/* Read the obstacles. */
|
||||
map_load_segment(f, filename, iti_segment_line_loader, "iti",
|
||||
&map->iti_arr, &map->iti_sz, sizeof *map->iti_arr,
|
||||
MAX_ITI_COUNT, &line);
|
||||
|
||||
/* Close file and return. */
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void map_destroy() {
|
||||
if (!map)
|
||||
return;
|
||||
|
||||
/* Fields have been initialized to NULL, it is safe to call free() on them. */
|
||||
free(map->road_arr);
|
||||
free(map->wayp_arr);
|
||||
free(map->tlight_arr);
|
||||
free(map->stop_arr);
|
||||
free(map->obst_arr);
|
||||
free(map);
|
||||
map = NULL;
|
||||
}
|
||||
|
||||
void Map__read_obstacles_step(Map__read_obstacles_out *o) {
|
||||
/* TODO very inefficient */
|
||||
memcpy(o->obst, map->obst_arr, map->obst_sz * sizeof *o->obst);
|
||||
|
||||
/* The map file might contain fewer obstacles than Globals__obstnum. */
|
||||
for (size_t i = map->obst_sz; i < MAX_OBST_COUNT; i++) {
|
||||
o->obst[i].pot_pos.x = 0.f;
|
||||
o->obst[i].pot_pos.y = 0.f;
|
||||
o->obst[i].pot_since = -1.f;
|
||||
o->obst[i].pot_till = -1.f;
|
||||
}
|
||||
}
|
||||
|
||||
void Map__read_itinerary_step(Map__read_itinerary_out *o) {
|
||||
/* TODO very inefficient */
|
||||
memcpy(o->iti, map->iti_arr, map->iti_sz * sizeof *o->iti);
|
||||
|
||||
/* The map file might contain fewer itinerary steps than Globals__itinum. */
|
||||
for (size_t i = map->iti_sz; i < MAX_ITI_COUNT; i++) {
|
||||
o->iti[i].act = Globals__Stop;
|
||||
o->iti[i].param = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
void Map__read_traffic_lights_step(Map__read_traffic_lights_out *o) {
|
||||
assert (map->tlight_sz <= Globals__trafnum);
|
||||
for (size_t i = 0; i < map->tlight_sz; i++)
|
||||
o->tlights[i] = map->tlight_arr[i].tl;
|
||||
for (size_t i = map->tlight_sz; i < MAX_TL_COUNT; i++)
|
||||
o->tlights[i] = (Globals__param_tlight){ {-100, -100}, 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
bool colors_equal(const Globals__color *a, const Globals__color *b) {
|
||||
return a->red == b->red && a->green == b->green && a->blue == b->blue;
|
||||
}
|
||||
|
||||
bool isOnRoadLine1(road_t *rd, float x, float y,
|
||||
Globals__color *col, double *d, float *dir_x, float *dir_y) {
|
||||
//test that may be inside road area
|
||||
// -compute projection on line
|
||||
float px = 0.0;
|
||||
float py = 0.0;
|
||||
dirProjPoint(x, y, &(rd->u.line.startp), &(rd->u.line.endp), &px, &py);
|
||||
//-compare with ends of the segment
|
||||
if ((px <= fmax(rd->u.line.startp.x, rd->u.line.endp.x)+EPS) &&
|
||||
(px >= fmin(rd->u.line.startp.x, rd->u.line.endp.x)-EPS) &&
|
||||
(py <= fmax(rd->u.line.startp.y, rd->u.line.endp.y)+EPS) &&
|
||||
(py >= fmin(rd->u.line.startp.y, rd->u.line.endp.y)-EPS))
|
||||
//the projection is inside, compute distance to rd
|
||||
(*d) = distance(x, y, px, py);
|
||||
else
|
||||
//the projection is outside the segment
|
||||
// let us test the extremities:
|
||||
(*d) = fmin(distance(x,y,rd->u.line.startp.x,rd->u.line.startp.y),
|
||||
distance(x,y,rd->u.line.endp.x,rd->u.line.endp.y));
|
||||
|
||||
//-compare with the width of the road
|
||||
if ((*d) >= RD_SIZE_HALF_WIDTH) {
|
||||
log_debug("[geometry] (%.2f, %.2f) is too far from road %p (dist. %.2f)!\n",
|
||||
x, y, rd, *d);
|
||||
return false;
|
||||
}
|
||||
|
||||
(*col) = rd->color;
|
||||
(*dir_x) = rd->u.line.endp.x - rd->u.line.startp.x;
|
||||
(*dir_y) = rd->u.line.endp.y - rd->u.line.startp.y;
|
||||
|
||||
if ((*d) < RD_SIZE_LINE) {
|
||||
//distance less than width of the road line,
|
||||
//then on road with one color
|
||||
//log_debug("Position on road line: %f!\n", *d);
|
||||
}
|
||||
else {
|
||||
//otherwise, compute the side of the road
|
||||
// left or right using direction(x, y)->(px, py)
|
||||
double dirPX = px - x; /* -b where b = x1 - x2 */
|
||||
double dirPY = py - y; /* a where a = y2 - y1 */
|
||||
double sinDir = dirVProd(*dir_x, *dir_y, dirPX, dirPY);
|
||||
if (sinDir < 0) {
|
||||
//on left
|
||||
(*col) = COL_ROADLEFT;
|
||||
#ifndef MAP_BMP
|
||||
if ((*d) <= RD_SIZE_LINE2)
|
||||
col->green = (unsigned int)(255.*((*d)-1.0));
|
||||
#endif
|
||||
} else {
|
||||
//on right
|
||||
(*col) = COL_ROADRIGHT;
|
||||
#ifndef MAP_BMP
|
||||
if ((*d) <= RD_SIZE_LINE2)
|
||||
col->red = (unsigned int)(255.*((*d)-1.0));
|
||||
#endif
|
||||
}
|
||||
//log_debug("Position on road: %f!\n", *d);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isOnRoadLine2(road_t *rd, float x, float y,
|
||||
Globals__color *col, double *d, float *dir_x, float *dir_y) {
|
||||
/* TODO missing from original project */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOnRoadArc(/* IN */
|
||||
road_t *rd, float x, float y,
|
||||
/* OUT */
|
||||
Globals__color *col, double *d,
|
||||
float *dir_x, float *dir_y)
|
||||
{
|
||||
//center
|
||||
double cx = rd->u.arc.center.x;
|
||||
double cy = rd->u.arc.center.y;
|
||||
|
||||
//compute angle(in degrees) from center
|
||||
double a = lineAngle(cx, cy, x, y);
|
||||
|
||||
//compute signed distance to the circle c
|
||||
double dist_c = distance(cx, cy, x, y) - rd->u.arc.radius;
|
||||
|
||||
if (isInArc(a, rd->u.arc.start_angle,rd->u.arc.end_angle)) {
|
||||
//within the angle
|
||||
(*d) = fabs(dist_c);
|
||||
}
|
||||
else {
|
||||
//Point outside road angles,
|
||||
// consider the distance to extremities
|
||||
(*d) = fmin(distance(x,y,
|
||||
cx+rd->u.arc.radius*cos(toradian(rd->u.arc.start_angle)),
|
||||
cy+rd->u.arc.radius*sin(toradian(rd->u.arc.start_angle))),
|
||||
distance(x,y,
|
||||
cx+rd->u.arc.radius*cos(toradian(rd->u.arc.end_angle)),
|
||||
cy+rd->u.arc.radius*sin(toradian(rd->u.arc.end_angle))));
|
||||
}
|
||||
|
||||
if ((*d) >= RD_SIZE_HALF_WIDTH) {
|
||||
//log_debug("Position too far from road: %f!\n", (*d));
|
||||
return false;
|
||||
}
|
||||
|
||||
(*col) = rd->color;
|
||||
|
||||
//direction is normal to d(c, (x, y))
|
||||
//its sign depends on rotation
|
||||
if (rd->u.arc.start_angle < rd->u.arc.end_angle){//counterclockwise
|
||||
(*dir_x) = cy - y;
|
||||
(*dir_y) = x - cx;
|
||||
}
|
||||
else {//clockwise
|
||||
(*dir_x) = y - cy; /* a where a = y2 - y1 */
|
||||
(*dir_y) = cx - x; /* b where b = x1 - x2 */
|
||||
}
|
||||
|
||||
if ((*d) < RD_SIZE_LINE) {
|
||||
//distance less than width of the road line,
|
||||
//then on road with one color
|
||||
//log_debug("Point on road line: %f!\n", *d);
|
||||
} else {
|
||||
//otherwise, compute the side of the road
|
||||
// left or right using the sense(trigo or clock) of the road
|
||||
if (((rd->u.arc.start_angle < rd->u.arc.end_angle) //trigo dir
|
||||
&& dist_c < 0) ||
|
||||
((rd->u.arc.start_angle > rd->u.arc.end_angle) // clock dir
|
||||
&& dist_c > 0)) {
|
||||
(*col) = COL_ROADLEFT;
|
||||
#ifndef MAP_BMP
|
||||
if ((*d) <= RD_SIZE_LINE2)
|
||||
col->green = (unsigned int)(255.*((*d)-1.0));
|
||||
#endif
|
||||
} else {
|
||||
(*col) = COL_ROADRIGHT;
|
||||
#ifndef MAP_BMP
|
||||
if ((*d) <= RD_SIZE_LINE2)
|
||||
col->red = (unsigned int)(255.*((*d)-1.0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//log_debug("Point on road: %f!\n", *d);
|
||||
return true;
|
||||
}
|
||||
|
||||
int isOnTLight(int x, int y, int rd, float dir_x, float dir_y)
|
||||
{
|
||||
if (map->tlight_arr == NULL ||
|
||||
map->tlight_sz <= 0)
|
||||
return -1;
|
||||
//no traffic light
|
||||
|
||||
for (int i = 0; i < map->tlight_sz; i++) {
|
||||
tlight_t *tl = &map->tlight_arr[i];
|
||||
if (tl->road != rd)
|
||||
continue;
|
||||
double d = distance(x, y, tl->tl.ptl_pos.x, tl->tl.ptl_pos.y);
|
||||
|
||||
/* double cosdir = dirCos(tl->tl.ptl_pos.y - y, x - tl->tl.ptl_pos.x,
|
||||
dir_x, dir_y); */ //MS
|
||||
double cosdir = dirCos(tl->tl.ptl_pos.x-x, tl->tl.ptl_pos.y-y,
|
||||
dir_x, dir_y); //EA
|
||||
if (d < TL_VIEW && cosdir > TL_COSDIR)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool isAfterStop(int x, int y, int rid, float dir_x, float dir_y, int* tl)
|
||||
{
|
||||
(*tl) = -1;
|
||||
|
||||
if (map->stop_arr == NULL ||
|
||||
map->stop_sz <= 0)
|
||||
return false;
|
||||
//no stop points
|
||||
|
||||
for (int i = 0; i < map->stop_sz; i++) {
|
||||
stop_t *sp = &map->stop_arr[i];
|
||||
if (sp->road != rid)
|
||||
continue;
|
||||
// check the distance to the point
|
||||
road_t *rd = &map->road_arr[sp->road];
|
||||
if (rd->kind == RD_LINE_1 ||
|
||||
rd->kind == RD_LINE_2) {
|
||||
// line
|
||||
// - compute projection on roadline
|
||||
float px = 0.0;
|
||||
float py = 0.0;
|
||||
dirProjPoint(x, y, &(rd->u.line.startp), &(rd->u.line.endp), &px, &py);
|
||||
// - compare with the bounds of the stop point
|
||||
double dsp = distance(px, py, sp->position.x, sp->position.y);
|
||||
double dir_x = px - sp->position.x;
|
||||
double dir_y = py - sp->position.y;
|
||||
if (dsp >= (RD_SIZE_STOP-EPS) &&
|
||||
dsp <= (STP_AFTER+RD_SIZE_STOP+EPS) &&
|
||||
(dirProd(rd->dir_x, rd->dir_y, dir_x, dir_y) >= 0))
|
||||
{
|
||||
log_debug("[geometry] (%d, %d) is after stop %d (dist %.2f)\n",
|
||||
x, y, i, dsp);
|
||||
(*tl) = sp->sema;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_debug("Position too far/not AFTER point on line: %lf!\n", dsp);
|
||||
log_debug("rd->dir(%lf,%lf) <> dir(%lf,%lf)\n", rd->dir_x, rd->dir_y,
|
||||
dir_x, dir_y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// arc
|
||||
// -compute angle of point in degrees
|
||||
double apoint = lineAngle(rd->u.arc.center.x, rd->u.arc.center.y,
|
||||
sp->position.x, sp->position.y);
|
||||
double apos = lineAngle(rd->u.arc.center.x, rd->u.arc.center.y, x, y);
|
||||
double dsp = toradian(fabs(apoint - apos))*rd->u.arc.radius;
|
||||
if (dsp >= (RD_SIZE_STOP-EPS) &&
|
||||
dsp <= (STP_AFTER+RD_SIZE_STOP+EPS)) {
|
||||
// - check that the direction is AFTER
|
||||
if (fourAnglesInOrder(rd->u.arc.start_angle,
|
||||
apoint, apos,
|
||||
rd->u.arc.end_angle))
|
||||
{
|
||||
log_debug("Position AFTER point on arc: %lf!\n", apos);
|
||||
(*tl) = sp->sema;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_debug("Position too far/not AFTER point on arc: %lf!\n", apos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log_debug("Position too far/not AFTER point on arc: %lf degrees!\n", apos);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
isPositionOnPoint(float x, float y, road_t* rd, position_t* p, double pWidth)
|
||||
{
|
||||
if (rd->kind == RD_LINE_1 ||
|
||||
rd->kind == RD_LINE_2) { // line
|
||||
// - compute projection on road line
|
||||
float px = 0.0;
|
||||
float py = 0.0;
|
||||
position_t startp = {0, 0};
|
||||
position_t endp = {0, 0};
|
||||
|
||||
startp = (rd->u.line.startp);
|
||||
endp = (rd->u.line.endp);
|
||||
dirProjPoint(x, y, &(startp), &(endp), &px, &py);
|
||||
// - compare with the bounds of the waypoint
|
||||
double dwp = distance(px, py, p->x, p->y);
|
||||
if (dwp <= pWidth) {
|
||||
log_debug("Position near point on line: %lf!\n", dwp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
//log_debug("Position too far from point on line: %lf!\n", dwp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// arc
|
||||
// - compute angle of point in degrees
|
||||
double apoint = lineAngle(rd->u.arc.center.x, rd->u.arc.center.y, p->x, p->y);
|
||||
double apos = lineAngle(rd->u.arc.center.x, rd->u.arc.center.y, x, y);
|
||||
double dwp = toradian(fabs(apoint - apos))*rd->u.arc.radius;
|
||||
if (dwp <= pWidth) {
|
||||
log_debug("Position near point on arc: %lf!\n", dwp);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
log_debug("Position too far from point on arc: %lf!\n", dwp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Globals__color getColorPoint(int rid, float x, float y) {
|
||||
// first go through waypoints
|
||||
log_debug("[geometry] looking for waypoints at (%.2f, %.2f) on road %d\n",
|
||||
x, y, rid);
|
||||
for (int i = 0; i < map->wayp_sz; i++) {
|
||||
waypoint_t *wp = &map->wayp_arr[i];
|
||||
if (wp->road != rid)
|
||||
{
|
||||
log_debug("Waypoint not on road %d!\n", rid);
|
||||
continue;
|
||||
}
|
||||
road_t *rd = &map->road_arr[wp->road];
|
||||
// waitpoints are ruban
|
||||
if (isPositionOnPoint(x, y, rd, &(wp->position), RD_SIZE_WAYPOINT)) {
|
||||
return COL_WAYPOINT;
|
||||
//one waypoint by position
|
||||
}
|
||||
}
|
||||
log_debug("[geometry] finished walking waypoints\n");
|
||||
|
||||
// then go to stop points
|
||||
log_debug("[geometry] looking for stops at (%.2f, %.2f) on road %d\n",
|
||||
x, y, rid);
|
||||
for (int i = 0; i < map->stop_sz; i++) {
|
||||
stop_t *sp = &map->stop_arr[i];
|
||||
if (sp->road != rid) {
|
||||
log_debug("Stop not on road %d!\n", rid);
|
||||
continue;
|
||||
}
|
||||
road_t *rd = &map->road_arr[sp->road];
|
||||
// stop points are ruban
|
||||
if (isPositionOnPoint(x, y, rd, &sp->position, RD_SIZE_STOP)) {
|
||||
log_debug("[geometry] (%.2f, %.2f) at stop %d\n", x, y, i);
|
||||
return COL_STOP;
|
||||
//one stop by position
|
||||
}
|
||||
}
|
||||
log_debug("[geometry] finished walking stops\n");
|
||||
|
||||
return COL_OUT;
|
||||
}
|
||||
|
||||
DEFINE_HEPT_FUN(Map, lookup_pos, (Globals__position pos)) {
|
||||
float x = pos.x, y = pos.y;
|
||||
|
||||
out->data.on_road = false;
|
||||
out->data.color = COL_OUT;
|
||||
out->data.max_speed = SPEED_MIN;
|
||||
out->data.tl_number = -1;
|
||||
out->data.tl_required = false;
|
||||
out->data.dir_x = -1.0;
|
||||
out->data.dir_y = 0.0;
|
||||
|
||||
log_debug("[geometry] querying pos (%.2f, %.2f)\n", x, y);
|
||||
if (map == NULL)
|
||||
log_fatal("[geometry] map has not been initialized\n");
|
||||
|
||||
int min_rd = -1;
|
||||
double min_d = 700.;
|
||||
for (int rid = 0; rid < map->road_sz; rid++) {
|
||||
road_t *rd = &map->road_arr[rid];
|
||||
double d = 0.;
|
||||
Globals__color col = COL_OUT;
|
||||
bool onRoad = false;
|
||||
float dir_X = 0.0;
|
||||
float dir_Y = 0.0;
|
||||
switch (rd->kind) {
|
||||
case RD_LINE_1:
|
||||
onRoad = isOnRoadLine1(rd, x, y, &col, &d, &dir_X, &dir_Y);
|
||||
break;
|
||||
case RD_LINE_2:
|
||||
onRoad = isOnRoadLine2(rd, x, y, &col, &d, &dir_X, &dir_Y);
|
||||
break;
|
||||
case RD_ARC:
|
||||
onRoad = isOnRoadArc(rd, x, y, &col, &d, &dir_X, &dir_Y);
|
||||
break;
|
||||
case RD_OTHER:
|
||||
break;
|
||||
}
|
||||
|
||||
if (onRoad && (d < min_d)) {
|
||||
min_d = d;
|
||||
min_rd = rid;
|
||||
out->data.color = col;
|
||||
out->data.dir_x = dir_X;
|
||||
out->data.dir_y = dir_Y;
|
||||
out->data.max_speed = map->road_arr[min_rd].max_speed;
|
||||
/* Update color when a waypoint or stop. */
|
||||
col = getColorPoint(rid, x, y);
|
||||
if (colors_equal(&col, &COL_OUT))
|
||||
out->data.color = out->data.color;
|
||||
else if (colors_equal(&col, &COL_STOP)) {
|
||||
/* TODO: update red color */
|
||||
out->data.color = col;
|
||||
}
|
||||
else {
|
||||
/* TODO: update green color */
|
||||
out->data.color = col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the return type. */
|
||||
if (min_rd >= 0) {
|
||||
log_debug("[geometry] (%.2f, %.2f) is on road %d\n", x, y, min_rd);
|
||||
out->data.on_road = true;
|
||||
int tl = -1;
|
||||
out->data.tl_number =
|
||||
isOnTLight(x, y, min_rd, out->data.dir_x, out->data.dir_y);
|
||||
out->data.tl_required = isAfterStop(x, y, min_rd,
|
||||
out->data.dir_x, out->data.dir_y, &tl);
|
||||
if(out->data.tl_required) {
|
||||
if (tl != out->data.tl_number) {
|
||||
log_debug("Warning: on TL %ld != ", out->data.tl_number);
|
||||
log_debug("after TL %d!\n", tl);
|
||||
}
|
||||
out->data.tl_number = tl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Log the result. */
|
||||
log_debug("[geometry] { on_road = %d; color = (%d, %d, %d);"
|
||||
" dir = (%2.2f, %2.2f); tl = (%d, %d); }\n",
|
||||
out->data.on_road,
|
||||
out->data.color.red, out->data.color.green, out->data.color.blue,
|
||||
out->data.dir_x, out->data.dir_y,
|
||||
out->data.tl_number, out->data.tl_required);
|
||||
}
|
||||
|
||||
|
||||
void play_asset_wav(SDL_AudioDeviceID audio_device, asset_wav_t *wav) {
|
||||
if (!audio_device) {
|
||||
log_info("[sdl] no audio device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_QueueAudio(audio_device, wav->buffer, wav->size))
|
||||
log_fatal("[sdl] could not queue audio\n");
|
||||
}
|
||||
|
||||
asset_wav_t collision, wrong_dir, exit_road, light_run, speed_excess;
|
||||
SDL_AudioDeviceID audio_device = 0;
|
||||
|
||||
DEFINE_HEPT_FUN(Map, soundEffects, (Globals__event evt, Globals__status sta)) {
|
||||
if (sta == Globals__Preparing)
|
||||
return;
|
||||
if (evt.exitRoad) {
|
||||
play_asset_wav(audio_device, &exit_road);
|
||||
log_info("[audio] car left the road\n");
|
||||
} else if (evt.collisionEvent) {
|
||||
play_asset_wav(audio_device, &collision);
|
||||
log_info("[audio] car has collided with an obstacle\n");
|
||||
} else if (evt.dirEvent) {
|
||||
play_asset_wav(audio_device, &wrong_dir);
|
||||
log_info("[audio] car goes in the wrong direction\n");
|
||||
} else if (evt.lightRun) {
|
||||
play_asset_wav(audio_device, &light_run);
|
||||
log_info("[audio] car has run a red light\n");
|
||||
} else if (evt.speedExcess) {
|
||||
play_asset_wav(audio_device, &speed_excess);
|
||||
log_info("[audio] car is going too fast\n");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user