Skip to content

Commit 322875a

Browse files
committed
Performance tweaks
1 parent 88954fc commit 322875a

3 files changed

Lines changed: 73 additions & 35 deletions

File tree

Sanchez.Processing/ImageProcessing/Projection/ReprojectRowOperation.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ namespace Sanchez.Processing.ImageProcessing.Projection;
1414

1515
public class ReprojectRowOperation
1616
{
17-
1817
private static readonly ConcurrentDictionary<int, LatitudeCalculations> LatitudeCalculationCache = new();
1918

2019
private readonly Registration _registration;
@@ -100,10 +99,10 @@ private LatitudeCalculations CalculateGeostationaryLatitude(int y)
10099
var target = _target;
101100
var yOffset = _yOffset;
102101

103-
return LatitudeCalculationCache.GetOrAdd(y, _ =>
102+
return LatitudeCalculationCache.GetOrAdd(y, yValue =>
104103
{
105104
// Convert pixel row to latitude
106-
var projectionY = ProjectionAngleConverter.FromY(y, target.Height + yOffset * 2);
105+
var projectionY = ProjectionAngleConverter.FromY(yValue, target.Height + yOffset * 2);
107106

108107
// Perform and cache intermediary geostationary latitude calculations
109108
return GeostationaryProjection.LatitudeCalculations(projectionY);

Sanchez.Processing/Projections/GeostationaryProjection.cs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,39 @@ public static class GeostationaryProjection
1212
{
1313
private const double RadiusPolarSquared = RadiusPolar * RadiusPolar;
1414
private const double RadiusEquatorSquared = RadiusEquator * RadiusEquator;
15+
16+
// Pre-computed constant to avoid division in hot path
17+
private const double RadiusRatio = RadiusEquatorSquared / RadiusPolarSquared;
18+
19+
// Pre-computed constant for latitude calculations
20+
private const double EccentricitySquared = Eccentricity * Eccentricity;
21+
private const double LatitudeScaleFactor = RadiusPolarSquared / RadiusEquatorSquared;
1522

23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1624
public static LatitudeCalculations LatitudeCalculations(double latitude)
1725
{
18-
var geocentricLatitude = Atan(RadiusPolarSquared / RadiusEquatorSquared * Tan(latitude));
26+
// Pre-compute values that are used multiple times
27+
var geocentricLatitude = Atan(LatitudeScaleFactor * Tan(latitude));
1928
var cosLatitude = Cos(geocentricLatitude);
2029
var sinLatitude = Sin(geocentricLatitude);
30+
31+
// Cache the cosine squared value which is used in multiple places
32+
var cosLatitudeSquared = cosLatitude * cosLatitude;
2133

22-
var rc = RadiusPolar / Sqrt(1 - Eccentricity * Eccentricity * cosLatitude * cosLatitude);
34+
var rc = RadiusPolar / Sqrt(1 - EccentricitySquared * cosLatitudeSquared);
2335
var sz = rc * sinLatitude;
36+
var sz2 = sz * sz;
2437

25-
var calculations = new LatitudeCalculations
38+
// Fill out the struct all at once to avoid unnecessary assignments
39+
return new LatitudeCalculations
2640
{
2741
CosLatitude = cosLatitude,
2842
Rc = rc,
2943
Sz = sz,
30-
Sz2 = sz * sz
44+
Sz2 = sz2,
45+
RcCosLatitude = rc * cosLatitude,
46+
RadiusRatioSz2 = RadiusRatio * sz2
3147
};
32-
33-
calculations.RcCosLatitude = calculations.Rc * calculations.CosLatitude;
34-
calculations.RadiusRatioSz2 = RadiusEquatorSquared / RadiusPolarSquared * calculations.Sz2;
35-
36-
return calculations;
3748
}
3849

3950
/// <summary>
@@ -48,6 +59,7 @@ public static LatitudeCalculations LatitudeCalculations(double latitude)
4859
/// <param name="definition">satellite definition</param>
4960
/// <param name="scanningX">calculated horizontal scanning angle in radians</param>
5061
/// <param name="scanningY">calculated vertical scanning angle in radians</param>
62+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5163
public static void ToScanningAngle(double latitude, double longitude, SatelliteDefinition definition, out double scanningX, out double scanningY)
5264
{
5365
var latitudeCalculations = LatitudeCalculations(latitude);
@@ -57,14 +69,21 @@ public static void ToScanningAngle(double latitude, double longitude, SatelliteD
5769
/// <summary>
5870
/// Converts a latitude and longitude to a geostationary image scanning angle.
5971
/// </summary>
60-
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
72+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
6173
public static void ToScanningAngle(LatitudeCalculations latitudeCalculations, double longitude, SatelliteDefinition definition, out double scanningX, out double scanningY)
6274
{
6375
var satelliteLongitude = definition.Longitude;
6476
var satelliteHeight = definition.Height + RadiusEquator;
6577

66-
var sx = satelliteHeight - latitudeCalculations.RcCosLatitude * Cos(longitude - satelliteLongitude);
67-
var sy = -latitudeCalculations.RcCosLatitude * Sin(longitude - satelliteLongitude);
78+
// Calculate longitude difference just once
79+
var longitudeDifference = longitude - satelliteLongitude;
80+
var cosLongDiff = Cos(longitudeDifference);
81+
var sinLongDiff = Sin(longitudeDifference);
82+
83+
var rcCosLat = latitudeCalculations.RcCosLatitude;
84+
85+
var sx = satelliteHeight - rcCosLat * cosLongDiff;
86+
var sy = -rcCosLat * sinLongDiff;
6887
var sy2 = sy * sy;
6988

7089
// Check if geodetic angle is visible from satellite
@@ -75,7 +94,10 @@ public static void ToScanningAngle(LatitudeCalculations latitudeCalculations, do
7594
}
7695

7796
// Calculate (x,y) scanning angle
78-
scanningX = Asin(-sy / Sqrt(sx * sx + sy2 + latitudeCalculations.Sz2));
97+
// Pre-compute the denominator for scanning angle calculations
98+
var sqrtTerm = Sqrt(sx * sx + sy2 + latitudeCalculations.Sz2);
99+
100+
scanningX = Asin(-sy / sqrtTerm);
79101
scanningY = Atan(latitudeCalculations.Sz / sx);
80102
}
81103
}

Sanchez.Processing/Projections/ReverseGeostationaryProjection.cs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,26 @@ public static class ReverseGeostationaryProjection
1212
{
1313
private const double RadiusPolarSquared = RadiusPolar * RadiusPolar;
1414
private const double RadiusEquatorSquared = RadiusEquator * RadiusEquator;
15+
16+
// Pre-computed constant to avoid division in hot path
17+
private const double RadiusRatio = RadiusEquatorSquared / RadiusPolarSquared;
1518

16-
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
19+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
1720
public static VerticalScanningCalculations VerticalScanningCalculations(double scanningY, double satelliteHeight)
1821
{
19-
var calculations = new VerticalScanningCalculations
22+
var cosY = Cos(scanningY);
23+
var sinY = Sin(scanningY);
24+
var adjustedHeight = satelliteHeight + RadiusEquator;
25+
26+
// Calculate directly instead of multiple property assignments
27+
return new VerticalScanningCalculations
2028
{
21-
CosY = Cos(scanningY),
22-
SinY = Sin(scanningY),
23-
SatelliteHeight = satelliteHeight + RadiusEquator
29+
CosY = cosY,
30+
SinY = sinY,
31+
SatelliteHeight = adjustedHeight,
32+
C = adjustedHeight * adjustedHeight - RadiusEquatorSquared,
33+
T = cosY * cosY + RadiusRatio * sinY * sinY
2434
};
25-
26-
calculations.C = calculations.SatelliteHeight * calculations.SatelliteHeight - RadiusEquatorSquared;
27-
calculations.T = calculations.CosY * calculations.CosY + RadiusEquatorSquared / RadiusPolarSquared * calculations.SinY * calculations.SinY;
28-
29-
return calculations;
3035
}
3136

3237
/// <summary>
@@ -41,7 +46,8 @@ public static VerticalScanningCalculations VerticalScanningCalculations(double s
4146
/// <param name="definition">satellite definition</param>
4247
/// <param name="latitude">calculated latitude in radians</param>
4348
/// <param name="longitude">calculated longitude in radians</param>
44-
public static void ToLatitudeLongitude(double scanningX, double scanningY, double satelliteLongitude, double satelliteHeight, out double latitude, out double longitude)
49+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
50+
public static void ToLatitudeLongitude(double scanningX, double scanningY, double satelliteLongitude, double satelliteHeight, out double latitude, out double longitude)
4551
{
4652
var verticalCalculations = VerticalScanningCalculations(scanningY, satelliteHeight);
4753
ToLatitudeLongitude(scanningX, verticalCalculations, satelliteLongitude, out latitude, out longitude);
@@ -55,31 +61,42 @@ public static void ToLatitudeLongitude(double scanningX, double scanningY, doubl
5561
/// <param name="satelliteLongitude">satellite longitude</param>
5662
/// <param name="latitude">calculated latitude in radians</param>
5763
/// <param name="longitude">calculated longitude in radians</param>
58-
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
64+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
5965
public static void ToLatitudeLongitude(
60-
double scanningX, VerticalScanningCalculations verticalScanningCalculations, double satelliteLongitude, out double latitude, out double longitude)
66+
double scanningX, VerticalScanningCalculations verticalScanningCalculations, double satelliteLongitude, out double latitude, out double longitude)
6167
{
6268
var satelliteHeight = verticalScanningCalculations.SatelliteHeight;
6369

70+
// Pre-compute trigonometric values
6471
var cosX = Cos(scanningX);
6572
var sinX = Sin(scanningX);
73+
var cosXSquared = cosX * cosX;
6674

6775
var cosY = verticalScanningCalculations.CosY;
6876
var sinY = verticalScanningCalculations.SinY;
6977
var t = verticalScanningCalculations.T;
7078
var c = verticalScanningCalculations.C;
7179

72-
var a = sinX * sinX + cosX * cosX * t;
80+
// Calculate quadratic formula components
81+
var a = sinX * sinX + cosXSquared * t;
7382
var b = -2 * satelliteHeight * cosX * cosY;
83+
var discr = b * b - 4 * a * c;
84+
85+
// Inline sqrt calculation for better performance
86+
var rs = (-b - Sqrt(discr)) / (2 * a);
7487

75-
var rs = (-b - Sqrt(b * b - 4 * a * c)) / (2 * a);
76-
88+
// Pre-compute these values once as they're used multiple times
7789
var sx = rs * cosX * cosY;
7890
var sy = -rs * sinX;
7991
var sz = rs * cosX * sinY;
80-
81-
latitude = Atan(RadiusEquatorSquared / RadiusPolarSquared * (sz / Sqrt((satelliteHeight - sx) * (satelliteHeight - sx) + sy * sy)));
82-
longitude = (satelliteLongitude - Atan(sy / (satelliteHeight - sx))).NormaliseLongitude();
92+
93+
// Calculate distance term once
94+
var satMinusSx = satelliteHeight - sx;
95+
var distSqr = satMinusSx * satMinusSx + sy * sy;
96+
97+
// Calculate latitude and longitude
98+
latitude = Atan(RadiusRatio * (sz / Sqrt(distSqr)));
99+
longitude = (satelliteLongitude - Atan(sy / satMinusSx)).NormaliseLongitude();
83100
}
84101
}
85102

0 commit comments

Comments
 (0)