diff --git a/lib_com/options.h b/lib_com/options.h index 5906991cdfdee9af54778d11f6c64f32df921be8..b78976fe89c0d8af9a08e0375aac98d69e96b6df 100755 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -152,6 +152,7 @@ #define ISM_BITRATE_SWITCHING /* Issue 115: Support for Bitrate Switching in ISM */ #define SBA_SPAR_HARM /* Issue 92: maintenance of the SBA SPAR functions */ #define FIX_155_HP20_ISSUE /* Issue 155: apply hp20 on all input channels instead of just 2 channels */ +#define EFAP_FIX_POLY /* Issue 167: fix bug in EFAP polygon selection */ diff --git a/lib_dec/ivas_efap.c b/lib_dec/ivas_efap.c index 602fd2416152a81bf52ae8b16197121e63513dd7..482edfb6432c4bb7477382b2fd1ae912e0825a33 100644 --- a/lib_dec/ivas_efap.c +++ b/lib_dec/ivas_efap.c @@ -83,7 +83,7 @@ static void get_poly_gains( const float azi, const float ele, const float aziPol static float get_tri_gain( const float A[2], const float B[2], const float C[2], const float P_minus_A[2] ); -#if defined( DEBUG_EFAP_POLY_TOFILE ) +#ifdef DEBUG_EFAP_POLY_TOFILE static void get_poly_select( EFAP_POLYSET_DATA *polyData ); #endif @@ -96,11 +96,13 @@ static void add_vertex( EFAP_VERTEX *vtxArray, const float azi, const float ele, static void efap_sort_s( int16_t *x, int16_t *idx, const int16_t len ); - static float vertex_distance( const EFAP_VERTEX *vtxArray, const EFAP_LS_TRIANGLE tri, const int16_t vtxIdx ); static float point_plane_distance( const float P1[3], const float P2[3], const float P3[3], const float X[3] ); +#ifdef EFAP_FIX_POLY +static float point_poly_distance( const EFAP_POLYSET poly, const float X[3] ); +#endif static void efap_crossp( const float *v1, const float *v2, float *v ); static int16_t find_int_in_tri( const EFAP_LS_TRIANGLE *tri, const int16_t n, const int16_t r, int16_t *pos ); @@ -125,6 +127,9 @@ static int16_t in_poly( const float P[2], const EFAP_POLYSET poly ); static int16_t in_tri( float A[2], float B[2], float C[2], float P_minus_A[2] ); +#ifdef EFAP_FIX_POLY +static void sph2cart( const float azi, const float ele, float *pos ); +#endif /*-----------------------------------------------------------------------* * Global function definitions @@ -462,14 +467,14 @@ static ivas_error poly_init( efap->polyData.numPoly = finalLength; -#if defined( DEBUG_EFAP_POLY_TOFILE ) +#ifdef DEBUG_EFAP_POLY_TOFILE get_poly_select( &efap->polyData ); #endif return error; } -#if defined( DEBUG_EFAP_POLY_TOFILE ) +#ifdef DEBUG_EFAP_POLY_TOFILE static void get_poly_select( EFAP_POLYSET_DATA *polyData /* o : Polygon data structure */ ) @@ -1497,9 +1502,13 @@ static void add_vertex( vtxArray[pos].ele = ( ( -180.0f > tmp ) ? -180.0f : tmp ); /* Converting spherical coordinates to cartesians, assuming radius = 1 */ +#ifdef EFAP_FIX_POLY + sph2cart( vtxArray[pos].azi, vtxArray[pos].ele, &vtxArray[pos].pos[0] ); +#else vtxArray[pos].pos[0] = cosf( vtxArray[pos].azi * PI_OVER_180 ) * cosf( vtxArray[pos].ele * PI_OVER_180 ); vtxArray[pos].pos[1] = sinf( vtxArray[pos].azi * PI_OVER_180 ) * cosf( vtxArray[pos].ele * PI_OVER_180 ); vtxArray[pos].pos[2] = sinf( vtxArray[pos].ele * PI_OVER_180 ); +#endif /* Computing the index defined by idx = idxAziTmp + 181 * idxEleTmp */ @@ -1591,11 +1600,32 @@ static float vertex_distance( return point_plane_distance( A, B, C, P ); } +#ifdef EFAP_FIX_POLY +/*-------------------------------------------------------------------------* + * point_plane_distance() + * + * Compute the signed distance between a point and polygon + *-------------------------------------------------------------------------*/ + +static float point_poly_distance( + const EFAP_POLYSET poly, /* i : The polygon which forms a plane */ + const float X[3] /* i : Cartesian coordinates of the point of interest */ +) +{ + float P1[3], P2[3], P3[3]; + + sph2cart( poly.polyAzi[0], poly.polyEle[0], &P1[0] ); + sph2cart( poly.polyAzi[1], poly.polyEle[1], &P2[0] ); + sph2cart( poly.polyAzi[2], poly.polyEle[2], &P3[0] ); + + return point_plane_distance( P1, P2, P3, X ); +} +#endif /*-------------------------------------------------------------------------* * point_plane_distance() * - * Compute the signed distance between a point a given plane + * Compute the signed distance between a point and a given plane *-------------------------------------------------------------------------*/ static float point_plane_distance( @@ -2082,16 +2112,63 @@ static int16_t get_poly_num( ) { int16_t i; +#ifdef EFAP_FIX_POLY + int16_t num_poly, found_poly; + int16_t poly_tmp[EFAP_MAX_CHAN_NUM], poly_dist[EFAP_MAX_CHAN_NUM]; + + float dist_tmp; + float pos[3]; + + num_poly = 0; + sph2cart( P[0], P[1], &pos[0] ); + + /* Filter the polygon list with a fast 2d check */ +#endif for ( i = 0; i < polyData->numPoly; ++i ) { if ( in_poly( P, polyData->polysetArray[i] ) ) { +#ifdef EFAP_FIX_POLY + /* select only polygons which are visible from the point */ + dist_tmp = point_poly_distance( polyData->polysetArray[i], pos ); + if ( dist_tmp == 0 ) + { + return i; + } + else if ( dist_tmp > 0 ) + { + poly_tmp[num_poly] = i; + poly_dist[num_poly] = dist_tmp; + num_poly++; + } +#else return i; +#endif + } + } +#ifdef EFAP_FIX_POLY + if ( num_poly == 0 ) + { + return -1; + } + + /* select the polygon with the smallest distance */ + found_poly = poly_tmp[0]; + dist_tmp = poly_dist[0]; + for ( i = 1; i < num_poly; i++ ) + { + if ( poly_dist[i] < dist_tmp ) + { + found_poly = poly_tmp[i]; + dist_tmp = poly_dist[i]; } } + return found_poly; +#else return -1; +#endif } @@ -2216,7 +2293,7 @@ static int16_t in_tri( S[0] = ( matInv[0][0] * P_minus_A[0] ) + ( matInv[0][1] * P_minus_A[1] ); S[1] = ( matInv[1][0] * P_minus_A[0] ) + ( matInv[1][1] * P_minus_A[1] ); - /* Checking if we are in the triangle; For the theory, check Christian Borss article, section 3.2 */ + /* Checking if we are in the triangle; For the theory, check Christian Borss article, section 3.2 */ if ( S[0] < -thresh || S[1] < -thresh || S[0] + S[1] > 1 + thresh ) { return 0; @@ -2226,3 +2303,20 @@ static int16_t in_tri( return 1; } } + +/*-------------------------------------------------------------------------* + * sph2cart() + * + * Converts a vertex position to cartesian coordinates + *-------------------------------------------------------------------------*/ + +static void sph2cart( + const float azi, /* i : Azimuth in degrees */ + const float ele, /* i : Elevation in degrees */ + float *pos /* o : Cartesian coordinates vector (x, y, z) */ +) +{ + pos[0] = cosf( azi * PI_OVER_180 ) * cosf( ele * PI_OVER_180 ); + pos[1] = sinf( azi * PI_OVER_180 ) * cosf( ele * PI_OVER_180 ); + pos[2] = sinf( ele * PI_OVER_180 ); +} diff --git a/scripts/pyaudio3dtools/EFAP.py b/scripts/pyaudio3dtools/EFAP.py index e5b4219cc0feea1e898674c805ed979dd3e593cf..5014cd168cc9a2a7f4e0df05d8124ad2578ff5c0 100644 --- a/scripts/pyaudio3dtools/EFAP.py +++ b/scripts/pyaudio3dtools/EFAP.py @@ -744,18 +744,40 @@ class EFAP: raise ValueError(f"Angles cannot be NaNs : ({azimuth}, {elevation})") azimuth, elevation = wrap_angles(azimuth, elevation) + point_pos = [ + np.cos(np.deg2rad(azimuth)) * np.cos(np.deg2rad(elevation)), + np.sin(np.deg2rad(azimuth)) * np.cos(np.deg2rad(elevation)), + np.sin(np.deg2rad(elevation)), + ] - # find the polygon corresponding to the given point - found_poly = None - mod = None + # filter the polygon list with a quick 2d check + found_polys = [] for poly in self.polys: in_poly, mod = self._in_polygon(azimuth, elevation, poly) if in_poly: - found_poly = poly - break - else: + found_polys.append((poly, mod)) + + if not found_polys: raise AssertionError("Unexpected error during panning") + # find a visible polygon with the smallest distance + dist = [] + + for poly, mod in found_polys: + surface = self.verts[poly] + d = self._point_plane_dist( + surface[0].pos, + surface[1].pos, + surface[2].pos, + point_pos, + ) + if d >= 0: + dist.append(d) + else: + dist.append(np.inf) + + found_poly, mod = found_polys[np.argmin(dist)] + # compute gains for the polygon vertices poly_gain = self._pan_EFAP_poly(azimuth, elevation, found_poly, mod)