2025-01-09 13:35:23 +01:00
# include "projection.h"
# include "logger.h"
# include "common/geodetic/vincentys_calculations.h" // TODOREWORK MOVE OUT
2025-05-27 18:42:18 +01:00
# include "projection/standard/proj_json.h"
2025-01-09 13:35:23 +01:00
# include "raytrace/gcp_compute.h"
namespace satdump
{
2025-05-27 18:42:18 +01:00
namespace projection
2025-01-09 13:35:23 +01:00
{
2025-04-15 19:06:12 +01:00
Projection : : Projection ( ) { }
2025-01-09 13:35:23 +01:00
Projection : : ~ Projection ( )
{
if ( fwd_type = = PROJ_STANDARD | | inv_type = = PROJ_STANDARD )
: : proj : : projection_free ( & std_proj ) ;
}
bool Projection : : init ( bool fwd , bool inv )
{
///////////////////////////////////////////////////////////
// We need image width/height
///////////////////////////////////////////////////////////
if ( d_cfg . contains ( " width " ) )
width = d_cfg [ " width " ] ;
else
throw satdump_exception ( " Image width must be present! " ) ;
if ( d_cfg . contains ( " height " ) )
height = d_cfg [ " height " ] ;
else
throw satdump_exception ( " Image height must be present! " ) ;
///////////////////////////////////////////////////////////
// Get channel pre-transform, if present
///////////////////////////////////////////////////////////
if ( d_cfg . contains ( " transform " ) )
transform = d_cfg [ " transform " ] ;
else
transform . init_none ( ) ;
2025-04-28 19:43:01 +02:00
///////////////////////////////////////////////////////////
// Get optional second channel pre-transform, if present
///////////////////////////////////////////////////////////
if ( d_cfg . contains ( " transform2 " ) )
{
has_2nd_transform = true ;
transform2 = d_cfg [ " transform2 " ] ;
}
2025-01-09 13:35:23 +01:00
///////////////////////////////////////////////////////////
// Attempt to setup a standard projection first
///////////////////////////////////////////////////////////
try
{
std_proj = d_cfg ;
if ( ! : : proj : : projection_setup ( & std_proj ) )
{
fwd_type = inv_type = PROJ_STANDARD ;
2025-03-13 11:22:37 +01:00
if ( d_cfg . contains ( " proj_timestamp " ) )
{
2025-05-24 20:59:22 +02:00
// logger->warn("Using projection timestamps for timestamp feedback. May be inacurate!"); // Disabled usually as it triggers... Everytime the proj is init
2025-03-13 11:22:37 +01:00
proj_timestamp = d_cfg [ " proj_timestamp " ] ;
}
2025-01-09 13:35:23 +01:00
return true ;
}
}
catch ( std : : exception & )
{
logger - > trace ( " Not a standard projection! " ) ;
}
///////////////////////////////////////////////////////////
2025-02-03 07:48:52 +01:00
// If this didn't work, we can attempt a raytraced proj
2025-01-09 13:35:23 +01:00
///////////////////////////////////////////////////////////
try
{
raytracer = get_satellite_raytracer ( d_cfg ) ;
if ( raytracer )
{
fwd_type = PROJ_INVALID ;
inv_type = PROJ_RAYTRACER ;
if ( fwd )
{
logger - > critical ( " Forward on raytrace is imperfect! " ) ;
auto gcps = compute_gcps ( d_cfg ) ;
2025-01-17 18:12:23 +01:00
tps_fwd = std : : make_shared < satdump : : proj : : LatLonTpsProjHelper > ( gcps , 1 , 0 ) ;
2025-01-09 13:35:23 +01:00
fwd_type = PROJ_THINPLATESPLINE ;
}
}
return true ;
}
2025-01-17 18:12:23 +01:00
catch ( std : : exception & e )
2025-01-09 13:35:23 +01:00
{
2025-01-17 18:12:23 +01:00
logger - > trace ( " Not a raytraced projection! : %s " , e . what ( ) ) ;
2025-01-09 13:35:23 +01:00
}
///////////////////////////////////////////////////////////
// And finally, the special case of simple GCPs
///////////////////////////////////////////////////////////
if ( d_cfg [ " type " ] = = " normal_gcps " )
logger - > critical ( " GCPs ALONE SUPPORT TBD! " ) ;
return false ;
}
2025-06-14 21:56:36 +02:00
bool Projection : : forward ( geodetic : : geodetic_coords_t pos , double & x , double & y , bool except )
2025-01-09 13:35:23 +01:00
{
if ( fwd_type = = PROJ_STANDARD )
{
pos . toDegs ( ) ; // TODOREWORK?
if ( : : proj : : projection_perform_fwd ( & std_proj , pos . lon , pos . lat , & x , & y ) )
return 1 ;
}
else if ( fwd_type = = PROJ_THINPLATESPLINE )
{
// Perform TPS
2025-01-17 18:12:23 +01:00
tps_fwd - > forward ( pos , x , y ) ;
2025-01-09 13:35:23 +01:00
return 0 ; // We do NOT want to run the ChannelTransform in reverse, TPS takes care of it already!
}
else
{
2025-06-14 21:56:36 +02:00
if ( except )
throw satdump_exception ( " Invalid forward projection type! " + d_cfg [ " type " ] . get < std : : string > ( ) ) ;
else
return 1 ;
2025-01-09 13:35:23 +01:00
}
// Run channel transform, might do nothing if no transform is needed
transform . reverse ( & x , & y ) ;
2025-04-28 19:43:01 +02:00
if ( has_2nd_transform )
transform2 . reverse ( & x , & y ) ;
2025-01-09 13:35:23 +01:00
return 0 ;
}
2025-06-14 21:56:36 +02:00
bool Projection : : inverse ( double x , double y , geodetic : : geodetic_coords_t & pos , double * otime , bool except )
2025-01-09 13:35:23 +01:00
{
// Run channel transform, might do nothing if no transform is needed
2025-04-28 19:43:01 +02:00
if ( has_2nd_transform )
transform2 . forward ( & x , & y ) ;
2025-01-09 13:35:23 +01:00
transform . forward ( & x , & y ) ;
if ( inv_type = = PROJ_STANDARD )
{
pos . toDegs ( ) ; // TODOREWORK?
2025-03-13 11:22:37 +01:00
if ( otime ! = nullptr )
* otime = proj_timestamp ;
2025-01-09 13:35:23 +01:00
return : : proj : : projection_perform_inv ( & std_proj , x , y , & pos . lon , & pos . lat ) ;
}
else if ( inv_type = = PROJ_RAYTRACER )
{
2025-01-12 20:25:45 +01:00
return raytracer - > get_position ( x , y , pos , otime ) ;
2025-01-09 13:35:23 +01:00
}
else
{
2025-06-14 21:56:36 +02:00
if ( except )
throw satdump_exception ( " Invalid inverse projection type! " + d_cfg [ " type " ] . get < std : : string > ( ) ) ;
else
return 1 ;
2025-01-09 13:35:23 +01:00
}
}
void Projection : : to_json ( nlohmann : : json & j ) const
{
j = d_cfg ;
2025-01-22 20:08:00 +01:00
if ( height ! = - 1 )
j [ " height " ] = height ;
if ( width ! = - 1 )
j [ " width " ] = width ;
2025-01-09 13:35:23 +01:00
}
void Projection : : from_json ( const nlohmann : : json & j )
{
d_cfg = j ; // TODOREWORK de-init?
2025-01-22 20:08:00 +01:00
height = j . contains ( " height " ) ? j [ " height " ] . get < int > ( ) : - 1 ;
width = j . contains ( " width " ) ? j [ " width " ] . get < int > ( ) : - 1 ;
2025-01-09 13:35:23 +01:00
fwd_type = PROJ_INVALID ;
inv_type = PROJ_INVALID ;
2025-09-04 01:49:14 +02:00
init ( 0 , 0 ) ;
2025-01-09 13:35:23 +01:00
}
2025-06-14 21:56:36 +02:00
} // namespace projection
2025-04-15 19:06:12 +01:00
} // namespace satdump