/// <inheritdoc/> public override void FillData() { using (Stream str = GetStream()) { if (str == null) { return; } using (BinaryReader br = new BinaryReader(str)) { str.Seek(DataOffset, SeekOrigin.Begin); str.Seek(176, SeekOrigin.Current); int numPhis = NumPhis; int numLambdas = NumLambdas; PhiLam[][] cvs = new PhiLam[numPhis][]; // Skip past rest of header for (int row = 0; row < numPhis; row++) { cvs[row] = new PhiLam[NumLambdas]; // NTV order is flipped compared with a normal CVS table for (int col = numLambdas - 1; col >= 0; col--) { // shift values are given in "arc-seconds" and need to be converted to radians. cvs[row][col].Phi = ReadDouble(br) * (Math.PI / 180) / 3600; cvs[row][col].Lambda = ReadDouble(br) * (Math.PI / 180) / 3600; } } Cvs = cvs; Filled = true; } } }
/// <inheritdoc></inheritdoc> public override void ReadHeader() { byte[] header = new byte[176]; using (Stream str = GetStream()) { if (str == null) return; // Read important header content using (BinaryReader br = new BinaryReader(str)) { br.Read(header, 0, 176); } } PhiLam ll; ll.Phi = GetDouble(header, 24); ll.Lambda = -GetDouble(header, 72); double urPhi = GetDouble(header, 40); double urLam = -GetDouble(header, 56); PhiLam cs = new PhiLam(); cs.Phi = GetDouble(header, 88); cs.Lambda = GetDouble(header, 104); NumLambdas = (int)(Math.Abs(urLam - ll.Lambda) / cs.Lambda + .5) + 1; NumPhis = (int)(Math.Abs(urPhi - ll.Phi) / cs.Phi + .5) + 1; ll.Lambda *= DEG_TO_RAD; ll.Phi *= DEG_TO_RAD; cs.Lambda *= DEG_TO_RAD; cs.Phi *= DEG_TO_RAD; LowerLeft = ll; CellSize = cs; }
/// <inheritdoc></inheritdoc> public override void FillData() { using Stream strLos = GetStream(); using Stream strLas = GetLasStream(); if (strLas == null || strLos == null) { return; } using BinaryReader brLas = new(strLas); using BinaryReader brLos = new(strLos); int numPhis = NumPhis; int numLambdas = NumLambdas; // .las/.los header is padded out to 1 full line of lambdas int offsetToData = ((NumLambdas + 1) * sizeof(Single)); brLas.BaseStream.Seek(offsetToData, SeekOrigin.Begin); brLos.BaseStream.Seek(offsetToData, SeekOrigin.Begin); PhiLam[][] cvs = new PhiLam[numPhis][]; for (int i = 0; i < numPhis; i++) { cvs[i] = new PhiLam[numLambdas]; brLas.ReadSingle(); // discard leading 'zero' brLos.ReadSingle(); // discard leading 'zero' cvs[i][0].Phi = brLas.ReadSingle() * SecToRad; cvs[i][0].Lambda = brLos.ReadSingle() * SecToRad; for (int j = 1; j < NumLambdas; j++) { cvs[i][j].Phi += brLas.ReadSingle() * SecToRad; cvs[i][j].Lambda += brLos.ReadSingle() * SecToRad; } } Cvs = cvs; Filled = true; }
/// <inheritdoc></inheritdoc> public override void FillData() { string numText; using (Stream str = GetStream()) { if (str == null) { return; } using (StreamReader sr = new StreamReader(str)) { sr.ReadLine(); numText = sr.ReadToEnd(); } } char[] separators = new[] { ' ', ',', ':', (char)10 }; string[] values = numText.Split(separators, StringSplitOptions.RemoveEmptyEntries); int p = 7; int numPhis = NumPhis; int numLambdas = NumLambdas; PhiLam[][] cvs = new PhiLam[numPhis][]; for (int i = 0; i < numPhis; i++) { cvs[i] = new PhiLam[numLambdas]; int iCheck = int.Parse(values[p]); if (iCheck != i) { throw new ProjectionException(ProjectionMessages.IndexMismatch); } p++; double lam = long.Parse(values[p]) * USecToRad; cvs[i][0].Lambda = lam; p++; double phi = long.Parse(values[p]) * USecToRad; cvs[i][0].Phi = phi; p++; for (int j = 1; j < NumLambdas; j++) { lam += long.Parse(values[p]) * USecToRad; cvs[i][j].Lambda = lam; p++; phi += long.Parse(values[p]) * USecToRad; cvs[i][j].Phi = phi; p++; } } Cvs = cvs; Filled = true; }
private static bool TryGrid(PhiLam input, NadTable table) { var wLam = table.LowerLeft.Lambda; var eLam = wLam + (table.NumLambdas - 1) * table.CellSize.Lambda; var sPhi = table.LowerLeft.Phi; var nPhi = sPhi + (table.NumPhis - 1) * table.CellSize.Lambda; if (input.Lambda < wLam || input.Lambda > eLam || input.Phi < sPhi || input.Phi > nPhi) { return(false); } return(true); }
/// <inheritdoc></inheritdoc> public override void ReadHeader() { byte[] header = new byte[176]; using (Stream str = GetStream()) { if (str == null) { return; } // Read important header content using (BinaryReader br = new BinaryReader(str)) { br.Read(header, 0, 176); } } PhiLam ll; ll.Phi = GetDouble(header, 24); ll.Lambda = -GetDouble(header, 72); double urPhi = GetDouble(header, 40); double urLam = -GetDouble(header, 56); PhiLam cs = new PhiLam(); cs.Phi = GetDouble(header, 88); cs.Lambda = GetDouble(header, 104); NumLambdas = (int)(Math.Abs(urLam - ll.Lambda) / cs.Lambda + .5) + 1; NumPhis = (int)(Math.Abs(urPhi - ll.Phi) / cs.Phi + .5) + 1; ll.Lambda *= DEG_TO_RAD; ll.Phi *= DEG_TO_RAD; cs.Lambda *= DEG_TO_RAD; cs.Phi *= DEG_TO_RAD; LowerLeft = ll; CellSize = cs; }
private static PhiLam NadInterpolate(PhiLam t, NadTable ct) { PhiLam result, remainder; result.Phi = HUGE_VAL; result.Lambda = HUGE_VAL; // find indices and normalize by the cell size (so fractions range from 0 to 1) int iLam = (int)Math.Floor(t.Lambda /= ct.CellSize.Lambda); int iPhi = (int)Math.Floor(t.Phi /= ct.CellSize.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 >= ct.NumLambdas) { if (iLam + 1 == ct.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 >= ct.NumPhis) { if (iPhi + 1 == ct.NumPhis && remainder.Phi < 1e-11) { iPhi--; remainder.Phi = 1; } else { return(result); } } PhiLam f00 = GetValue(iPhi, iLam, ct); PhiLam f01 = GetValue(iPhi + 1, iLam, ct); PhiLam f10 = GetValue(iPhi, iLam + 1, ct); PhiLam f11 = GetValue(iPhi + 1, iLam + 1, ct); // 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) double m00 = (1 - remainder.Lambda) * (1 - remainder.Phi); double m01 = (1 - remainder.Lambda) * remainder.Phi; double m10 = remainder.Lambda * (1 - remainder.Phi); double 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 static PhiLam Convert(PhiLam input, bool inverse, NadTable table) { if (input.Lambda == HUGE_VAL) { return(input); } // Normalize input to ll origin if (!table.Filled) { table.FillData(); } PhiLam tb = input; tb.Lambda -= table.LowerLeft.Lambda; tb.Phi -= table.LowerLeft.Phi; tb.Lambda = Proj.Adjlon(tb.Lambda - Math.PI) + Math.PI; PhiLam t = NadInterpolate(tb, table); if (inverse) { PhiLam del, dif; int i = MAX_TRY; if (t.Lambda == HUGE_VAL) { return(t); } t.Lambda = tb.Lambda + t.Lambda; t.Phi = tb.Phi - t.Phi; do { del = NadInterpolate(t, table); /* 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 == HUGE_VAL) { Debug.WriteLine(ProjectionMessages.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) > TOL && Math.Abs(dif.Phi) > TOL); if (i < 0) { Debug.WriteLine(ProjectionMessages.InvShiftConvergeFailed); t.Lambda = t.Phi = HUGE_VAL; return(t); } input.Lambda = Proj.Adjlon(t.Lambda + table.LowerLeft.Lambda); input.Phi = t.Phi + table.LowerLeft.Phi; } else { if (t.Lambda == HUGE_VAL) { input = t; } else { input.Lambda -= t.Lambda; input.Phi += t.Phi; } } return(input); }
/// <inheritdoc></inheritdoc> public override void FillData() { using (Stream str = GetStream()) { if (str == null) return; using (var br = new BinaryReader(str)) { int numPhis = NumPhis; int numLambdas = NumLambdas; PhiLam[][] cvs = new PhiLam[numPhis][]; // Skip past rest of header str.Seek(176, SeekOrigin.Begin); for (int row = 0; row < numPhis; row++) { cvs[row] = new PhiLam[numLambdas]; // NTV order is flipped compared with a normal CVS table for (int col = numLambdas - 1; col >= 0; col--) { // shift values are given in "arc-seconds" and need to be converted to radians. cvs[row][col].Phi = ReadDouble(br) * (Math.PI / 180) / 3600; cvs[row][col].Lambda = ReadDouble(br) * (Math.PI / 180) / 3600; } } Cvs = cvs; } } }
/// <summary> /// /// </summary> /// <param name="t"></param> /// <param name="ct"></param> /// <returns></returns> private static PhiLam NadInterpolate(PhiLam t, NadTable ct) { PhiLam result, remainder; result.Phi = HUGE_VAL; result.Lambda = HUGE_VAL; // find indices and normalize by the cell size (so fractions range from 0 to 1) int iLam = (int)Math.Floor(t.Lambda /= ct.CellSize.Lambda); int iPhi = (int)Math.Floor(t.Phi /= ct.CellSize.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 >= ct.NumLambdas) { if (iLam + 1 == ct.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 >= ct.NumPhis) { if (iPhi + 1 == ct.NumPhis && remainder.Phi < 1e-11) { iPhi--; remainder.Phi = 1; } else { return result; } } PhiLam f00 = GetValue(iPhi, iLam, ct); PhiLam f01 = GetValue(iPhi + 1, iLam, ct); PhiLam f10 = GetValue(iPhi, iLam + 1, ct); PhiLam f11 = GetValue(iPhi + 1, iLam + 1, ct); // 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) double m00 = (1 - remainder.Lambda) * (1 - remainder.Phi); double m01 = (1 - remainder.Lambda) * remainder.Phi; double m10 = remainder.Lambda * (1 - remainder.Phi); double 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 static PhiLam Convert(PhiLam input, bool inverse, NadTable table) { if (input.Lambda == HUGE_VAL) return input; // Normalize input to ll origin if (!table.Filled) table.FillData(); PhiLam tb = input; tb.Lambda -= table.LowerLeft.Lambda; tb.Phi -= table.LowerLeft.Phi; tb.Lambda = Proj.Adjlon(tb.Lambda - Math.PI) + Math.PI; PhiLam t = NadInterpolate(tb, table); if (inverse) { PhiLam del, dif; int i = MAX_TRY; if (t.Lambda == HUGE_VAL) return t; t.Lambda = tb.Lambda + t.Lambda; t.Phi = tb.Phi - t.Phi; do { del = NadInterpolate(t, table); /* 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 == HUGE_VAL) { Debug.WriteLine(ProjectionMessages.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) > TOL && Math.Abs(dif.Phi) > TOL); if (i < 0) { Debug.WriteLine(ProjectionMessages.InvShiftConvergeFailed); t.Lambda = t.Phi = HUGE_VAL; return t; } input.Lambda = Proj.Adjlon(t.Lambda + table.LowerLeft.Lambda); input.Phi = t.Phi + table.LowerLeft.Phi; } else { if (t.Lambda == HUGE_VAL) { input = t; } else { input.Lambda -= t.Lambda; input.Phi += t.Phi; } } return input; }
/// <inheritdoc></inheritdoc> public override void FillData() { string numText; using (Stream str = GetStream()) { if (str == null) return; using (StreamReader sr = new StreamReader(str)) { sr.ReadLine(); numText = sr.ReadToEnd(); } } char[] separators = new[] { ' ', ',', ':', (char)10 }; string[] values = numText.Split(separators, StringSplitOptions.RemoveEmptyEntries); int p = 7; int numPhis = NumPhis; int numLambdas = NumLambdas; PhiLam[][] cvs = new PhiLam[numPhis][]; for (int i = 0; i < numPhis; i++) { cvs[i] = new PhiLam[numLambdas]; int iCheck = int.Parse(values[p]); if (iCheck != i) { throw new ProjectionException(ProjectionMessages.IndexMismatch); } p++; double lam = long.Parse(values[p]) * USecToRad; cvs[i][0].Lambda = lam; p++; double phi = long.Parse(values[p]) * USecToRad; cvs[i][0].Phi = phi; p++; for (int j = 1; j < NumLambdas; j++) { lam += long.Parse(values[p]) * USecToRad; cvs[i][j].Lambda = lam; p++; phi += long.Parse(values[p]) * USecToRad; cvs[i][j].Phi = phi; p++; } } Cvs = cvs; Filled = true; }
/// <inheritdoc></inheritdoc> public override void FillData() { using (Stream strLos = GetStream()) using (Stream strLas = GetLasStream()) { if (strLas == null || strLos == null) return; using (BinaryReader brLas = new BinaryReader(strLas)) using (BinaryReader brLos = new BinaryReader(strLos)) { int numPhis = NumPhis; int numLambdas = NumLambdas; // .las/.los header is padded out to 1 full line of lambdas int offsetToData = ((NumLambdas + 1) * sizeof(Single)); brLas.BaseStream.Seek(offsetToData, SeekOrigin.Begin); brLos.BaseStream.Seek(offsetToData, SeekOrigin.Begin); PhiLam[][] cvs = new PhiLam[numPhis][]; for (int i = 0; i < numPhis; i++) { cvs[i] = new PhiLam[numLambdas]; brLas.ReadSingle(); // discard leading 'zero' brLos.ReadSingle(); // discard leading 'zero' cvs[i][0].Phi = brLas.ReadSingle() * SecToRad; cvs[i][0].Lambda = brLos.ReadSingle() * SecToRad; for (int j = 1; j < NumLambdas; j++) { cvs[i][j].Phi += brLas.ReadSingle() * SecToRad; cvs[i][j].Lambda += brLos.ReadSingle() * SecToRad; } } Cvs = cvs; Filled = true; } } }