private bool ReadHeader(byte[] headerBuffer, GridTable table) { var ll = new PhiLambda { Phi = GetBigEndianDouble(headerBuffer, 4 * 16 + 8), Lambda = -GetBigEndianDouble(headerBuffer, 7 * 16 + 8) }; var ur = new PhiLambda { Phi = GetBigEndianDouble(headerBuffer, 5 * 16 + 8), Lambda = -GetBigEndianDouble(headerBuffer, 6 * 16 + 8) }; var cs = new PhiLambda { Phi = GetBigEndianDouble(headerBuffer, 8 * 16 + 8), Lambda = -GetBigEndianDouble(headerBuffer, 9 * 16 + 8) }; table.NumLambdas = (int)(Math.Abs(ur.Lambda - ll.Lambda) / cs.Lambda + .5) + 1; table.NumPhis = (int)(Math.Abs(ur.Phi - ll.Phi) / cs.Phi + .5) + 1; table.LowerLeft = PhiLambda.DegreesToRadians(ll); table.UpperRight = PhiLambda.DegreesToRadians(ur); table.SizeOfGridCell = PhiLambda.DegreesToRadians(cs); return(true); }
/// <summary> /// Parses the grid table data /// </summary> /// <param name="table">The table to fill</param> /// <returns>true if the data could be read.</returns> internal override bool ReadData(GridTable table) { using (var brLos = new BinaryReader(OpenGridTableStream())) using (var brLas = new BinaryReader(OpenLasStream())) { var numPhis = table.NumPhis; var coeffs = new PhiLambda[numPhis][]; var numLambdas = table.NumLambdas; //position the stream var offset = sizeof(float) * (numLambdas + 1); brLas.BaseStream.Seek(offset, SeekOrigin.Current); brLos.BaseStream.Seek(offset, SeekOrigin.Current); for (var i = 0; i < numPhis; i++) { //Skip first 'zero' value brLas.ReadBytes(sizeof(float)); brLos.ReadBytes(sizeof(float)); coeffs[i] = new PhiLambda[numLambdas]; coeffs[i][0] = PhiLambda.ArcSecondsToRadians(brLas.ReadSingle(), brLos.ReadSingle()); for (var j = 1; j < numLambdas; j++) { coeffs[i][j] = coeffs[i][j - 1] + PhiLambda.ArcSecondsToRadians(brLas.ReadSingle(), brLos.ReadSingle()); } table.Coefficients = coeffs; } return(true); } }
/// <summary> /// Parses the grid table data /// </summary> /// <param name="table">The table to fill</param> /// <returns>true if the data could be read.</returns> internal override bool ReadData(GridTable table) { using (var s = OpenGridTableStream()) { s.Seek(_dataOffset + 176, SeekOrigin.Current); using (var br = new BinaryReader(s)) { var numPhis = table.NumPhis; var coeffs = new PhiLambda[numPhis][]; var numLambdas = table.NumLambdas; for (var row = 0; row < numPhis; row++) { coeffs[row] = new PhiLambda[numLambdas]; // NTV order is flipped compared with a normal CVS table for (var col = numLambdas - 1; col >= 0; col--) { // shift values are given in "arc-seconds" and need to be converted to radians. coeffs[row][col] = PhiLambda.ArcSecondsToRadians( ReadBigEndianDouble(br), ReadBigEndianDouble(br)); } } } } return(true); }
internal bool Applies(PhiLambda location, out GridTable table) { //Set inital return value table = null; //Test finer sub grid tables foreach (var subGridTable in _subGridTables) { if (subGridTable.Applies(location, out table)) { return(true); } } if (location.Lambda < LowerLeft.Lambda || location.Lambda > UpperRight.Lambda || location.Phi < LowerLeft.Phi || location.Phi > UpperRight.Phi) { return(false); } table = this; return(true); }
internal Coordinate Apply(Coordinate geoCoord, bool inverse) { var input = new PhiLambda { Lambda = geoCoord.X, Phi = geoCoord.Y }; if (input.Lambda == HugeValue) { return(geoCoord); } if (!_fullyLoaded) { lock (_lockReadData) { if (!_fullyLoaded) { _loader.ReadData(this); } _fullyLoaded = true; } } var output = Convert(input, inverse); geoCoord.X = output.Lambda; geoCoord.Y = output.Phi; return(geoCoord); }
public static PhiLambda ArcMicroSecondsToRadians(PhiLambda plInDegrees) { return(new PhiLambda { Lambda = ProjectionMath.ArcMicroSecondsToRadians(plInDegrees.Lambda), Phi = ProjectionMath.ArcMicroSecondsToRadians(plInDegrees.Phi) }); }
internal override bool ReadHeader(GridTable table) { using (var stream = OpenGridTableStream()) { var header = new byte[176]; if (stream.Read(header, 0, 176) != 176) { return(false); } table.LowerLeft = new PhiLambda { Phi = GetBigEndianDouble(header, 24), Lambda = -GetBigEndianDouble(header, 72) }; table.UpperRight = new PhiLambda { Phi = GetBigEndianDouble(header, 40), Lambda = -GetBigEndianDouble(header, 56) }; table.SizeOfGridCell = new PhiLambda { Phi = GetBigEndianDouble(header, 88), Lambda = -GetBigEndianDouble(header, 104) }; var size = table.UpperRight - table.LowerLeft; table.NumLambdas = (int)(Math.Abs(size.Lambda) / table.SizeOfGridCell.Lambda + 0.5) + 1; table.NumPhis = (int)(Math.Abs(size.Phi) / table.SizeOfGridCell.Phi + 0.5) + 1; table.LowerLeft = PhiLambda.DegreesToRadians(table.LowerLeft); table.UpperRight = PhiLambda.DegreesToRadians(table.UpperRight); table.SizeOfGridCell = PhiLambda.DegreesToRadians(table.SizeOfGridCell); return(true); } }
internal override bool ReadData(GridTable table) { using (var br = new BinaryReader(OpenGridTableStream())) { br.BaseStream.Seek(176, SeekOrigin.Current); var coeffs = new PhiLambda[table.NumPhis][]; for (var row = 0; row < table.NumPhis; row++) { coeffs[row] = new PhiLambda[table.NumLambdas]; // NTV order is flipped compared with a normal CVS table for (var col = table.NumLambdas - 1; col >= 0; col--) { const double degToArcSec = (Math.PI / 180) / 3600; // shift values are given in "arc-seconds" and need to be converted to radians. coeffs[row][col].Phi = ReadBigEndianDouble(br) * degToArcSec; coeffs[row][col].Lambda = ReadBigEndianDouble(br) * degToArcSec; } } table.Coefficients = coeffs; return(true); } }
/// <summary> /// Parses the grid table header and returns an appropriate <see cref="GridTable"/> /// </summary> /// <param name="table">The grid tabel to initialize</param> /// <returns>true if the header could be read.</returns> internal override bool ReadHeader(GridTable table) { using (var br = new BinaryReader(OpenGridTableStream())) { br.BaseStream.Seek(64, SeekOrigin.Current); table.NumLambdas = br.ReadInt32(); table.NumPhis = br.ReadInt32(); br.ReadBytes(4); PhiLambda ll, cs; ll.Lambda = br.ReadSingle(); cs.Lambda = br.ReadSingle(); ll.Phi = br.ReadSingle(); cs.Phi = br.ReadSingle(); table.LowerLeft = PhiLambda.DegreesToRadians(ll); table.SizeOfGridCell = PhiLambda.DegreesToRadians(cs); table.UpperRight = ll + cs.Times(table.NumPhis, table.NumLambdas); return(true); } }
private PhiLambda InterpolateGrid(PhiLambda t) { PhiLambda result, remainder; result.Phi = HugeValue; result.Lambda = HugeValue; // find indices and normalize by the cell size (so fractions range from 0 to 1) var iLam = (int)Math.Floor(t.Lambda /= SizeOfGridCell.Lambda); var iPhi = (int)Math.Floor(t.Phi /= SizeOfGridCell.Phi); // use the index to determine the remainder remainder.Lambda = t.Lambda - iLam; remainder.Phi = t.Phi - iPhi; //int offLam = 0; // normally we look to the right and bottom neighbor cells //int offPhi = 0; //if (remainder.Lambda < .5) offLam = -1; // look to cell left of the current cell //if (remainder.Phi < .5) offPhi = -1; // look to cell above the of the current cell //// because the fractional weights are between cells, we need to adjust the //// "remainder" so that it is now relative to the center of the top left //// cell, taking into account that the definition of the top left cell //// depends on whether the original remainder was larger than .5 //remainder.Phi = (remainder.Phi > .5) ? remainder.Phi - .5 : remainder.Phi + .5; //remainder.Lambda = (remainder.Lambda > .5) ? remainder.Lambda - .5 : remainder.Phi + .5; if (iLam < 0) { if (iLam == -1 && remainder.Lambda > 0.99999999999) { iLam++; remainder.Lambda = 0; } else { return(result); } } else if (iLam + 1 >= NumLambdas) { if (iLam + 1 == NumLambdas && remainder.Lambda < 1e-11) { iLam--; } else { return(result); } } if (iPhi < 0) { if (iPhi == -1 && remainder.Phi > 0.99999999999) { iPhi++; remainder.Phi = 0; } else { return(result); } } else if (iPhi + 1 >= NumPhis) { if (iPhi + 1 == NumPhis && remainder.Phi < 1e-11) { iPhi--; remainder.Phi = 1; } else { return(result); } } var f00 = GetValue(iPhi, iLam); var f01 = GetValue(iPhi + 1, iLam); var f10 = GetValue(iPhi, iLam + 1); var f11 = GetValue(iPhi + 1, iLam + 1); // The cell weight is equivalent to the area of a cell sized square centered // on the actual point that overlaps with the cell. // Since the overlap must add up to 1, any portion that does not overlap // on the left must overlap on the right, hence (1-remainder.Lambda) var m00 = (1 - remainder.Lambda) * (1 - remainder.Phi); var m01 = (1 - remainder.Lambda) * remainder.Phi; var m10 = remainder.Lambda * (1 - remainder.Phi); var m11 = remainder.Lambda * remainder.Phi; result.Lambda = m00 * f00.Lambda + m01 * f01.Lambda + m10 * f10.Lambda + m11 * f11.Lambda; result.Phi = m00 * f00.Phi + m01 * f01.Phi + m10 * f10.Phi + m11 * f11.Phi; return(result); }
private PhiLambda Convert(PhiLambda input, bool inverse) { var tb = input; tb.Lambda -= LowerLeft.Lambda; tb.Phi -= LowerLeft.Phi; tb.Lambda = ProjectionMath.NormalizeLongitude(tb.Lambda - Math.PI) + Math.PI; var t = InterpolateGrid(tb); if (inverse) { PhiLambda dif; int i = MaxIterations; if (t.Lambda == HugeValue) { return(t); } t.Lambda = tb.Lambda + t.Lambda; t.Phi = tb.Phi - t.Phi; do { var del = InterpolateGrid(t); /* This case used to return failure, but I have * changed it to return the first order approximation * of the inverse shift. This avoids cases where the * grid shift *into* this grid came from another grid. * While we aren't returning optimally correct results * I feel a close result in this case is better than * no result. NFW * To demonstrate use -112.5839956 49.4914451 against * the NTv2 grid shift file from Canada. */ if (del.Lambda == HugeValue) { Debug.WriteLine("InverseShiftFailed"); break; } t.Lambda -= dif.Lambda = t.Lambda - del.Lambda - tb.Lambda; t.Phi -= dif.Phi = t.Phi + del.Phi - tb.Phi; } while (i-- > 0 && Math.Abs(dif.Lambda) > Tolerance && Math.Abs(dif.Phi) > Tolerance); if (i < 0) { Debug.WriteLine("InvShiftConvergeFailed"); t.Lambda = t.Phi = HugeValue; return(t); } input.Lambda = ProjectionMath.NormalizeLongitude(t.Lambda + LowerLeft.Lambda); input.Phi = t.Phi + LowerLeft.Phi; } else { if (t.Lambda == HugeValue) { input = t; } else { input.Lambda -= t.Lambda; input.Phi += t.Phi; } } return(input); }
internal override bool ReadData(GridTable table) { using (var sr = new StreamReader(OpenGridTableStream())) { //Skip first 2 lines sr.ReadLine(); sr.ReadLine(); var phiIndex = -1; var lambdaIndex = 0; double phi = 0, lambda = 0; var coeff = new PhiLambda[table.NumPhis][]; while (!sr.EndOfStream) { var line = sr.ReadLine(); if (string.IsNullOrEmpty(line)) { continue; } var posColon = line.IndexOf(':'); string[] values; int valueIndex; if (posColon > 0) { phiIndex = int.Parse(line.Substring(0, posColon), NumberStyles.Integer); coeff[phiIndex] = new PhiLambda[table.NumLambdas]; line = line.Substring(posColon + 1); values = line.Split(new[] { ' ' }); lambda = ProjectionMath.ArcSecondsToRadians(long.Parse(values[0], NumberStyles.Integer)); phi = ProjectionMath.ArcSecondsToRadians(long.Parse(values[1], NumberStyles.Integer)); coeff[phiIndex][0].Phi = phi; coeff[phiIndex][0].Lambda = lambda; lambdaIndex = 1; valueIndex = 2; } else { values = line.Split(new[] { ' ' }); valueIndex = 0; } if (phiIndex >= 0) { while (lambdaIndex < table.NumLambdas) { lambda += ProjectionMath.ArcMicroSecondsToRadians( long.Parse(values[valueIndex++], NumberStyles.Integer)); phi += ProjectionMath.ArcMicroSecondsToRadians( long.Parse(values[valueIndex++], NumberStyles.Integer)); coeff[phiIndex][lambdaIndex].Phi = phi; coeff[phiIndex][lambdaIndex].Lambda = lambda; lambdaIndex++; } } } table.Coefficients = coeff; } return(true); }