示例#1
0
        //**********************************************************************
        //							nad_ctable_load()
        //
        //		Load the data portion of a ctable formatted grid.
        //**********************************************************************
        public static bool nad_ctable_load(projCtx ctx, CTABLE ct, Stream fid)
        {
            try
            {
                fid.Seek(80 + 16 + 16 + 8 + 4, SeekOrigin.Begin);         // 80+16+16+8+4 ?= sizeof(struct CTABLE)

                // read all the actual shift values
                int a_size = ct.lim.lam * ct.lim.phi;

                ct.cvs = new LP[a_size];

                BinaryReader br = new BinaryReader(fid);
                for (int i = 0; i < a_size; i++)
                {
                    ct.cvs[i].lam = br.ReadSingle();
                    ct.cvs[i].phi = br.ReadSingle();
                }
            }
            catch
            {
                ct.cvs = null;

#if DEBUG
                Console.Error.WriteLine("ctable loading failed on fread() - binary incompatible?");
#endif
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            return(true);
        }
示例#2
0
        //**********************************************************************
        //								nad_init()
        //
        //		Read a datum shift file in any of the supported binary formats.
        //**********************************************************************
        public static CTABLE nad_init(projCtx ctx, string name)
        {
            ctx.last_errno = 0;

            // --------------------------------------------------------------------
            //		Open the file using the usual search rules.
            // --------------------------------------------------------------------

            Stream fid = Proj.pj_open_lib(ctx, name, FileAccess.Read);

            if (fid == null)
            {
                return(null);
            }

            CTABLE ct = nad_ctable_init(ctx, fid);

            if (ct != null)
            {
                if (!nad_ctable_load(ctx, ct, fid))
                {
                    nad_free(ct);
                    ct = null;
                }
            }

            fid.Close();
            return(ct);
        }
示例#3
0
 //**********************************************************************
 //								nad_free()
 //
 //		Free a CTABLE grid shift structure produced by nad_init().
 //**********************************************************************
 public static void nad_free(CTABLE ct)
 {
     if (ct != null)
     {
         ct.cvs = null;
     }
 }
示例#4
0
        //**********************************************************************
        //							nad_ctable2_load()
        //
        //		Load the data portion of a ctable2 formatted grid.
        //**********************************************************************
        public static bool nad_ctable2_load(projCtx ctx, CTABLE ct, Stream fid)
        {
            try
            {
                fid.Seek(160, SeekOrigin.Begin);

                // read all the actual shift values
                int a_size = ct.lim.lam * ct.lim.phi;

                ct.cvs = new LP[a_size];

                BinaryReader br = new BinaryReader(fid);

                if (IS_LSB)
                {
                    for (int i = 0; i < a_size; i++)
                    {
                        ct.cvs[i].lam = br.ReadSingle();
                        ct.cvs[i].phi = br.ReadSingle();
                    }
                }
                else
                {
                    byte[] buf = br.ReadBytes(a_size * 8);
                    swap_words(buf, 0, 4, a_size * 2);

                    using (BinaryReader br2 = new BinaryReader(new MemoryStream(buf)))
                    {
                        for (int i = 0; i < a_size; i++)
                        {
                            ct.cvs[i].lam = br2.ReadSingle();
                            ct.cvs[i].phi = br2.ReadSingle();
                        }
                    }
                }

                return(true);
            }
            catch
            {
                ct.cvs = null;

#if DEBUG
                Proj.pj_log(ctx, PJ_LOG.ERROR, "ctable2 loading failed on fread() - binary incompatible?");
#endif

                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }
        }
示例#5
0
        //**********************************************************************
        //							nad_ctable_init()
        //
        //		Read the header portion of a "ctable" format grid.
        //**********************************************************************
        public static CTABLE nad_ctable_init(projCtx ctx, Stream fid)
        {
            try
            {
                CTABLE ct    = new CTABLE();
                byte[] tmpID = new byte[80];

                // read the table header
                fid.Read(tmpID, 0, 80);

                BinaryReader br = new BinaryReader(fid);
                ct.ll.lam  = br.ReadDouble();
                ct.ll.phi  = br.ReadDouble();
                ct.del.lam = br.ReadDouble();
                ct.del.phi = br.ReadDouble();

                ct.lim.lam = br.ReadInt32();
                ct.lim.phi = br.ReadInt32();
                br.ReadInt32();                 // FLP* cvs

                // do some minimal validation to ensure the structure isn't corrupt
                if (ct.lim.lam < 1 || ct.lim.lam > 100000 || ct.lim.phi < 1 || ct.lim.phi > 100000)
                {
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(null);
                }

                ct.id = Encoding.ASCII.GetString(tmpID);
                ct.id = ct.id.Trim();               // trim white space and newlines off id

                ct.cvs = null;

                return(ct);
            }
            catch
            {
                Proj.pj_ctx_set_errno(ctx, -38);
                return(null);
            }
        }
示例#6
0
        //**********************************************************************
        //							nad_ctable2_init()
        //
        //		Read the header portion of a "ctable2" format grid.
        //**********************************************************************
        public static CTABLE nad_ctable2_init(projCtx ctx, Stream fid)
        {
            try
            {
                CTABLE ct     = new CTABLE();
                byte[] header = new byte[160];

                // read the table header
                fid.Read(header, 0, 160);

                if (!IS_LSB)
                {
                    swap_words(header, 96, 8, 4);
                    swap_words(header, 128, 4, 2);
                }

                MemoryStream mem       = new MemoryStream(header);
                BinaryReader br        = new BinaryReader(mem);
                byte[]       signature = new byte[16];
                byte[]       tmpID     = new byte[80];

                signature = br.ReadBytes(16);
                string sig = Encoding.ASCII.GetString(signature);
                if (sig.Substring(0, 9) != "CTABLE V2")
                {
                    Proj.pj_log(ctx, PJ_LOG.ERROR, "ctable2 - wrong header!");
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(null);
                }

                // read the table header
                tmpID = br.ReadBytes(80);

                ct.ll.lam  = br.ReadDouble();
                ct.ll.phi  = br.ReadDouble();
                ct.del.lam = br.ReadDouble();
                ct.del.phi = br.ReadDouble();

                ct.lim.lam = br.ReadInt32();
                ct.lim.phi = br.ReadInt32();

                // do some minimal validation to ensure the structure isn't corrupt
                if (ct.lim.lam < 1 || ct.lim.lam > 100000 || ct.lim.phi < 1 || ct.lim.phi > 100000)
                {
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(null);
                }

                ct.id = Encoding.ASCII.GetString(tmpID);
                ct.id = ct.id.Trim();               // trim white space and newlines off id

                ct.cvs = null;

                return(ct);
            }
            catch
            {
                Proj.pj_ctx_set_errno(ctx, -38);
                return(null);
            }
        }
示例#7
0
        //**********************************************************************
        //						pj_gridinfo_init_gtx()
        //
        //		Load a NOAA .gtx vertical datum shift file.
        //**********************************************************************
        static bool pj_gridinfo_init_gtx(projCtx ctx, FileStream fid, PJ_GRIDINFO gi)
        {
            byte[] header = new byte[40];
            CTABLE ct;
            double xorigin, yorigin, xstep, ystep;
            int    rows, columns;

            // --------------------------------------------------------------------
            //		Read the header.
            // --------------------------------------------------------------------
            if (fid.Read(header, 0, 40) != 40)
            {
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            // --------------------------------------------------------------------
            //		Regularize fields of interest and extract.
            // --------------------------------------------------------------------
            if (IS_LSB)
            {
                swap_words(header, 0, 8, 4);
                swap_words(header, 32, 4, 2);
            }

            yorigin = BitConverter.ToDouble(header, 0);
            xorigin = BitConverter.ToDouble(header, 8);
            ystep   = BitConverter.ToDouble(header, 16);
            xstep   = BitConverter.ToDouble(header, 24);

            rows    = BitConverter.ToInt32(header, 32);
            columns = BitConverter.ToInt32(header, 36);

            if (xorigin < -360 || xorigin > 360 ||
                yorigin < -90 || yorigin > 90)
            {
                Console.WriteLine("gtx file header has invalid extents, corrupt?");
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            // --------------------------------------------------------------------
            //		Fill in CTABLE structure.
            // --------------------------------------------------------------------
            ct    = new CTABLE();
            ct.id = "GTX Vertical Grid Shift File";

            ct.ll.lam  = xorigin;
            ct.ll.phi  = yorigin;
            ct.del.lam = xstep;
            ct.del.phi = ystep;
            ct.lim.lam = columns;
            ct.lim.phi = rows;

            // some GTX files come in 0-360 and we shift them back into the
            // expected -180 to 180 range if possible. This does not solve
            // problems with grids spanning the dateline.
            if (ct.ll.lam >= 180.0)
            {
                ct.ll.lam -= 360.0;
            }

#if !DEBUG
            if (ct.ll.lam >= 0.0 && ct.ll.lam + ct.del.lam * ct.lim.lam > 180.0)
            {
                Console.Error.WriteLine("This GTX spans the dateline! This will cause problems.");
            }

            Console.Error.WriteLine("GTX {0}x{1}: LL=({2},{3}) UR=({4},{5})", ct.lim.lam, ct.lim.phi, ct.ll.lam, ct.ll.phi, ct.ll.lam + (columns - 1) * xstep, ct.ll.phi + (rows - 1) * ystep);
#endif

            ct.ll.lam  *= Proj.DEG_TO_RAD;
            ct.ll.phi  *= Proj.DEG_TO_RAD;
            ct.del.lam *= Proj.DEG_TO_RAD;
            ct.del.phi *= Proj.DEG_TO_RAD;
            ct.cvs      = null;

            gi.ct          = ct;
            gi.grid_offset = 40;
            gi.format      = "gtx";

            return(true);
        }
示例#8
0
        //**********************************************************************
        //							pj_gridinfo_init()
        //
        //		Open and parse header details from a datum gridshift file
        //		returning a list of PJ_GRIDINFOs for the grids in that
        //		file. This superceeds use of nad_init() for modern
        //		applications.
        //**********************************************************************
        public static PJ_GRIDINFO pj_gridinfo_init(projCtx ctx, string gridname)
        {
            Libc.errno     = Proj.pj_errno = 0;
            ctx.last_errno = 0;

            // --------------------------------------------------------------------
            //		Initialize a GRIDINFO with stub info we would use if it
            //		cannot be loaded.
            // --------------------------------------------------------------------
            PJ_GRIDINFO gilist = new PJ_GRIDINFO();

            gilist.gridname    = gridname;
            gilist.filename    = null;
            gilist.format      = "missing";
            gilist.grid_offset = 0;
            gilist.ct          = null;
            gilist.next        = null;

            // --------------------------------------------------------------------
            //		Open the file using the usual search rules.
            // --------------------------------------------------------------------
            FileStream fp = Proj.pj_open_lib(ctx, gridname, FileAccess.Read);

            if (fp == null)
            {
                Proj.pj_errno  = Libc.errno;
                ctx.last_errno = 0;               // don't treat as a persistent error
                return(gilist);
            }

            gilist.filename = gridname;

            // --------------------------------------------------------------------
            //		Load a header, to determine the file type.
            // --------------------------------------------------------------------
            byte[] header = new byte[160];

            try
            {
                if (fp.Read(header, 0, header.Length) != header.Length)
                {
                    fp.Close();
                    header = null;
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(gilist);
                }
            }
            catch
            {
                fp.Close();
                header = null;
                Proj.pj_ctx_set_errno(ctx, -38);
                return(gilist);
            }

            fp.Seek(0, SeekOrigin.Begin);

            // --------------------------------------------------------------------
            //		Determine file type.
            // --------------------------------------------------------------------
            if (Encoding.ASCII.GetString(header, 0, 6) == "HEADER" &&
                Encoding.ASCII.GetString(header, 96, 6) == "W GRID" &&
                Encoding.ASCII.GetString(header, 144, 16) == "TO      NAD83   ")
            {
                pj_gridinfo_init_ntv1(ctx, fp, gilist);
            }
            else if (Encoding.ASCII.GetString(header, 0, 8) == "NUM_OREC" &&
                     Encoding.ASCII.GetString(header, 48, 7) == "GS_TYPE")
            {
                pj_gridinfo_init_ntv2(ctx, fp, gilist);
            }
            else if (gridname.Length > 4 && gridname.EndsWith("gtx", StringComparison.CurrentCultureIgnoreCase))
            {
                pj_gridinfo_init_gtx(ctx, fp, gilist);
            }
            else if (Encoding.ASCII.GetString(header, 0, 9) == "CTABLE V2")
            {
                CTABLE ct = nad_ctable2_init(ctx, fp);

                gilist.format = "ctable2";
                gilist.ct     = ct;

                Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, "Ctable2 {0} {1}x{2}: LL=({3},{4}) UR=({5},{6})",
                            ct.id, ct.lim.lam, ct.lim.phi, ct.ll.lam * Proj.RAD_TO_DEG, ct.ll.phi * Proj.RAD_TO_DEG,
                            (ct.ll.lam + (ct.lim.lam - 1) * ct.del.lam) * Proj.RAD_TO_DEG, (ct.ll.phi + (ct.lim.phi - 1) * ct.del.phi) * Proj.RAD_TO_DEG);
            }
            else
            {
                CTABLE ct = nad_ctable_init(ctx, fp);

                if (ct == null)
                {
                    Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, "CTABLE ct is NULL.");
                }
                else
                {
                    gilist.format = "ctable";
                    gilist.ct     = ct;

                    Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, "Ctable {0} {1}x{2}: LL=({3},{4}) UR=({5},{6})",
                                ct.id, ct.lim.lam, ct.lim.phi, ct.ll.lam * Proj.RAD_TO_DEG, ct.ll.phi * Proj.RAD_TO_DEG,
                                (ct.ll.lam + (ct.lim.lam - 1) * ct.del.lam) * Proj.RAD_TO_DEG, (ct.ll.phi + (ct.lim.phi - 1) * ct.del.phi) * Proj.RAD_TO_DEG);
                }
            }

            fp.Close();

            return(gilist);
        }
示例#9
0
        //**********************************************************************
        //						pj_gridinfo_init_ntv2()
        //
        //		Load a ntv2 (.gsb) file.
        //**********************************************************************
        static bool pj_gridinfo_init_ntv2(projCtx ctx, FileStream fid, PJ_GRIDINFO gilist)
        {
            byte[] header = new byte[11 * 16];

            // --------------------------------------------------------------------
            //		Read the overview header.
            // --------------------------------------------------------------------
            try
            {
                if (fid.Read(header, 0, header.Length) != header.Length)
                {
                    header = null;
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(false);
                }
            }
            catch
            {
                header = null;
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            // --------------------------------------------------------------------
            //		Byte swap interesting fields if needed.
            // --------------------------------------------------------------------
            if (!IS_LSB)
            {
                swap_words(header, 8, 4, 1);
                swap_words(header, 8 + 16, 4, 1);
                swap_words(header, 8 + 32, 4, 1);
                swap_words(header, 8 + 7 * 16, 8, 1);
                swap_words(header, 8 + 8 * 16, 8, 1);
                swap_words(header, 8 + 9 * 16, 8, 1);
                swap_words(header, 8 + 10 * 16, 8, 1);
            }

            // --------------------------------------------------------------------
            //		Get the subfile count out ... all we really use for now.
            // --------------------------------------------------------------------
            int num_subfiles = BitConverter.ToInt32(header, 8 + 32);

            // ====================================================================
            //		Step through the subfiles, creating a PJ_GRIDINFO for each.
            // ====================================================================
            for (int subfile = 0; subfile < num_subfiles; subfile++)
            {
                // --------------------------------------------------------------------
                //		Read header.
                // --------------------------------------------------------------------
                try
                {
                    if (fid.Read(header, 0, header.Length) != header.Length)
                    {
                        header = null;
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }
                }
                catch
                {
                    header = null;
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(false);
                }

                if (Encoding.ASCII.GetString(header, 0, 8).StartsWith("SUB_NAME"))
                {
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(false);
                }

                // --------------------------------------------------------------------
                //		Byte swap interesting fields if needed.
                // --------------------------------------------------------------------
                if (!IS_LSB)
                {
                    swap_words(header, 8 + 16 * 4, 8, 1);
                    swap_words(header, 8 + 16 * 5, 8, 1);
                    swap_words(header, 8 + 16 * 6, 8, 1);
                    swap_words(header, 8 + 16 * 7, 8, 1);
                    swap_words(header, +8 + 16 * 8, 8, 1);
                    swap_words(header, 8 + 16 * 9, 8, 1);
                    swap_words(header, 8 + 16 * 10, 4, 1);
                }

                // --------------------------------------------------------------------
                //		Initialize a corresponding "ct" structure.
                // --------------------------------------------------------------------
                CTABLE ct = new CTABLE();
                ct.id = Encoding.ASCII.GetString(header, 8, 8);

                ct.ll.lam = -BitConverter.ToDouble(header, 7 * 16 + 8);                 // W_LONG
                ct.ll.phi = BitConverter.ToDouble(header, 4 * 16 + 8);                  // S_LAT

                LP ur;
                ur.lam = -BitConverter.ToDouble(header, 6 * 16 + 8);                    // E_LONG
                ur.phi = BitConverter.ToDouble(header, 5 * 16 + 8);                     // N_LAT

                ct.del.lam = BitConverter.ToDouble(header, 9 * 16 + 8);
                ct.del.phi = BitConverter.ToDouble(header, 8 * 16 + 8);

                ct.lim.lam = (int)(Math.Abs(ur.lam - ct.ll.lam) / ct.del.lam + 0.5) + 1;
                ct.lim.phi = (int)(Math.Abs(ur.phi - ct.ll.phi) / ct.del.phi + 0.5) + 1;

#if DEBUG
                Console.Error.WriteLine("NTv2 {0} {1}x{2}: LL=({3},{4}) UR=({5},{6})", ct.id,
                                        ct.lim.lam, ct.lim.phi, ct.ll.lam / 3600.0, ct.ll.phi / 3600.0, ur.lam / 3600.0, ur.phi / 3600.0);
#endif

                ct.ll.lam  *= Proj.DEG_TO_RAD / 3600.0;
                ct.ll.phi  *= Proj.DEG_TO_RAD / 3600.0;
                ct.del.lam *= Proj.DEG_TO_RAD / 3600.0;
                ct.del.phi *= Proj.DEG_TO_RAD / 3600.0;

                int gs_count = BitConverter.ToInt32(header, 8 + 16 * 10);
                if (gs_count != ct.lim.lam * ct.lim.phi)
                {
                    Console.Error.WriteLine("GS_COUNT({0}) does not match expected cells ({1}x{2}={3})",
                                            gs_count, ct.lim.lam, ct.lim.phi, ct.lim.lam * ct.lim.phi);
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(false);
                }

                ct.cvs = null;

                PJ_GRIDINFO gi;

                // --------------------------------------------------------------------
                //		Create a new gridinfo for this if we aren't processing the
                //		1st subfile, and initialize our grid info.
                // --------------------------------------------------------------------
                if (subfile == 0)
                {
                    gi = gilist;
                }
                else
                {
                    gi          = new PJ_GRIDINFO();
                    gi.gridname = gilist.gridname;
                    gi.filename = gilist.filename;
                    gi.next     = null;
                }

                gi.ct          = ct;
                gi.format      = "ntv2";
                gi.grid_offset = fid.Position;

                // --------------------------------------------------------------------
                //		Attach to the correct list or sublist.
                // --------------------------------------------------------------------
                if (Encoding.ASCII.GetString(header, 24, 4) == "NONE")
                {
                    if (gi != gilist)
                    {
                        PJ_GRIDINFO lnk = gilist;
                        while (lnk.next != null)
                        {
                            lnk = lnk.next;
                        }
                        lnk.next = gi;
                    }
                }
                else
                {
                    PJ_GRIDINFO gp = pj_gridinfo_parent(gilist, Encoding.ASCII.GetString(header, 24, 8));

                    if (gp == null)
                    {
#if DEBUG
                        Console.Error.WriteLine("pj_gridinfo_init_ntv2(): failed to find parent {0} for {1}.",
                                                Encoding.ASCII.GetString(header, 24, 8), gi.ct.id);
#endif

                        PJ_GRIDINFO lnk = gilist;
                        while (lnk.next != null)
                        {
                            lnk = lnk.next;
                        }
                        lnk.next = gi;
                    }
                    else if (gp.child == null)
                    {
                        gp.child = gi;
                    }
                    else
                    {
                        PJ_GRIDINFO lnk = gp.child;
                        while (lnk.next != null)
                        {
                            lnk = lnk.next;
                        }
                        lnk.next = gi;
                    }
                }

                // --------------------------------------------------------------------
                //		Seek past the data.
                // --------------------------------------------------------------------
                fid.Seek(gs_count * 16, SeekOrigin.Current);
            }

            return(true);
        }
示例#10
0
        //**********************************************************************
        //						pj_gridinfo_init_ntv1()
        //
        //		Load an NTv1 style Canadian grid shift file.
        //**********************************************************************
        static bool pj_gridinfo_init_ntv1(projCtx ctx, FileStream fid, PJ_GRIDINFO gi)
        {
            byte[] header = new byte[176];

            // --------------------------------------------------------------------
            //		Read the header.
            // --------------------------------------------------------------------
            try
            {
                if (fid.Read(header, 0, header.Length) != header.Length)
                {
                    header = null;
                    Proj.pj_ctx_set_errno(ctx, -38);
                    return(false);
                }
            }
            catch
            {
                header = null;
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            // --------------------------------------------------------------------
            //		Regularize fields of interest.
            // --------------------------------------------------------------------
            if (IS_LSB)
            {
                swap_words(header, 8, 4, 1);
                swap_words(header, 24, 8, 1);
                swap_words(header, 40, 8, 1);
                swap_words(header, 56, 8, 1);
                swap_words(header, 72, 8, 1);
                swap_words(header, 88, 8, 1);
                swap_words(header, 104, 8, 1);
            }

            if (BitConverter.ToInt32(header, 8) != 12)
            {
                Console.Error.WriteLine("NTv1 grid shift file has wrong record count, corrupt?");
                Proj.pj_ctx_set_errno(ctx, -38);
                return(false);
            }

            // --------------------------------------------------------------------
            //		Fill in CTABLE structure.
            // --------------------------------------------------------------------
            CTABLE ct = new CTABLE();

            ct.id = "NTv1 Grid Shift File";

            ct.ll.lam = -BitConverter.ToDouble(header, 72);
            ct.ll.phi = BitConverter.ToDouble(header, 24);

            LP ur;

            ur.lam = -BitConverter.ToDouble(header, 56);
            ur.phi = BitConverter.ToDouble(header, 40);

            ct.del.lam = BitConverter.ToDouble(header, 104);
            ct.del.phi = BitConverter.ToDouble(header, 88);

            ct.lim.lam = (int)(Math.Abs(ur.lam - ct.ll.lam) / ct.del.lam + 0.5) + 1;
            ct.lim.phi = (int)(Math.Abs(ur.phi - ct.ll.phi) / ct.del.phi + 0.5) + 1;

#if DEBUG
            Console.Error.WriteLine("NTv1 {0}x{1}: LL=({2},{3}) UR=({4},{5})",
                                    ct.lim.lam, ct.lim.phi, ct.ll.lam, ct.ll.phi, ur.lam, ur.phi);
#endif

            ct.ll.lam  *= Proj.DEG_TO_RAD;
            ct.ll.phi  *= Proj.DEG_TO_RAD;
            ct.del.lam *= Proj.DEG_TO_RAD;
            ct.del.phi *= Proj.DEG_TO_RAD;
            ct.cvs      = null;

            gi.ct          = ct;
            gi.grid_offset = fid.Position;
            gi.format      = "ntv1";

            return(true);
        }
示例#11
0
        //**********************************************************************
        //							pj_gridinfo_load()
        //
        //		This function is intended to implement delayed loading of
        //		the data contents of a grid file. The header and related
        //		stuff are loaded by pj_gridinfo_init().
        //**********************************************************************
        public static bool pj_gridinfo_load(projCtx ctx, PJ_GRIDINFO gi)
        {
            if (gi == null || gi.ct == null)
            {
                return(false);
            }

            lock (gridlock)
            {
                if (gi.ct.cvs != null)
                {
                    return(true);
                }

                CTABLE ct_tmp = gi.ct.Clone();

                // --------------------------------------------------------------------
                //		Original platform specific CTable format.
                // --------------------------------------------------------------------
                if (gi.format == "ctable")
                {
                    FileStream fid = Proj.pj_open_lib(ctx, gi.filename, FileAccess.Read);
                    if (fid == null)
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    bool result = nad_ctable_load(ctx, ct_tmp, fid);

                    fid.Close();

                    gi.ct.cvs = ct_tmp.cvs;

                    return(result);
                }
                // --------------------------------------------------------------------
                //		CTable2 format.
                // --------------------------------------------------------------------
                else if (gi.format == "ctable2")
                {
                    FileStream fid = Proj.pj_open_lib(ctx, gi.filename, FileAccess.Read);
                    if (fid == null)
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    bool result = nad_ctable2_load(ctx, ct_tmp, fid);

                    fid.Close();

                    gi.ct.cvs = ct_tmp.cvs;

                    return(result);
                }

                // --------------------------------------------------------------------
                //		NTv1 format.
                //		We process one line at a time. Note that the array storage
                //		direction (e-w) is different in the NTv1 file and what
                //		the CTABLE is supposed to have. The phi/lam are also
                //		reversed, and we have to be aware of byte swapping.
                // --------------------------------------------------------------------
                if (gi.format == "ntv1")
                {
                    FileStream fid = Proj.pj_open_lib(ctx, gi.filename, FileAccess.Read);

                    if (fid == null)
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    fid.Seek(gi.grid_offset, SeekOrigin.Begin);

                    byte[] row_buf;
                    try
                    {
                        row_buf    = new byte[gi.ct.lim.lam * 2 * sizeof(double)];
                        ct_tmp.cvs = new LP[gi.ct.lim.lam * gi.ct.lim.phi];
                    }
                    catch
                    {
                        row_buf    = null;
                        ct_tmp.cvs = null;

                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    for (int row = 0; row < gi.ct.lim.phi; row++)
                    {
                        try
                        {
                            if (fid.Read(row_buf, 0, gi.ct.lim.lam * 2 * sizeof(double)) != gi.ct.lim.lam * 2 * sizeof(double))
                            {
                                row_buf    = null;
                                ct_tmp.cvs = null;

                                Proj.pj_ctx_set_errno(ctx, -38);
                                return(false);
                            }
                        }
                        catch
                        {
                            row_buf    = null;
                            ct_tmp.cvs = null;

                            Proj.pj_ctx_set_errno(ctx, -38);
                            return(false);
                        }

                        if (IS_LSB)
                        {
                            swap_words(row_buf, 8, gi.ct.lim.lam * 2);
                        }

                        // convert seconds to radians
                        int diff_seconds = 0;

                        for (int i = 0; i < gi.ct.lim.lam; i++)
                        {
                            int cvs = row * gi.ct.lim.lam + (gi.ct.lim.lam - i - 1);

                            ct_tmp.cvs[cvs].phi = BitConverter.ToDouble(row_buf, (diff_seconds++) * sizeof(double)) * ((Proj.PI / 180.0) / 3600.0);
                            ct_tmp.cvs[cvs].lam = BitConverter.ToDouble(row_buf, (diff_seconds++) * sizeof(double)) * ((Proj.PI / 180.0) / 3600.0);
                        }
                    }

                    row_buf = null;

                    fid.Close();

                    gi.ct.cvs = ct_tmp.cvs;

                    return(true);
                }

                // --------------------------------------------------------------------
                //		NTv2 format.
                //		We process one line at a time. Note that the array storage
                //		direction (e-w) is different in the NTv2 file and what
                //		the CTABLE is supposed to have. The phi/lam are also
                //		reversed, and we have to be aware of byte swapping.
                // --------------------------------------------------------------------
                if (gi.format == "ntv2")
                {
#if DEBUG
                    Console.Error.WriteLine("NTv2 - loading grid " + gi.ct.id);
#endif

                    FileStream fid = Proj.pj_open_lib(ctx, gi.filename, FileAccess.Read);

                    if (fid == null)
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    fid.Seek(gi.grid_offset, SeekOrigin.Begin);

                    byte[] row_buf;
                    try
                    {
                        row_buf    = new byte[gi.ct.lim.lam * 4 * sizeof(float)];
                        ct_tmp.cvs = new LP[gi.ct.lim.lam * gi.ct.lim.phi];
                    }
                    catch
                    {
                        row_buf    = null;
                        ct_tmp.cvs = null;

                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    for (int row = 0; row < gi.ct.lim.phi; row++)
                    {
                        try
                        {
                            if (fid.Read(row_buf, 0, gi.ct.lim.lam * 4 * sizeof(float)) != gi.ct.lim.lam * 4 * sizeof(float))
                            {
                                row_buf    = null;
                                ct_tmp.cvs = null;

                                Proj.pj_ctx_set_errno(ctx, -38);
                                return(false);
                            }
                        }
                        catch
                        {
                            row_buf    = null;
                            ct_tmp.cvs = null;

                            Proj.pj_ctx_set_errno(ctx, -38);
                            return(false);
                        }

                        if (!IS_LSB)
                        {
                            swap_words(row_buf, 4, gi.ct.lim.lam * 4);
                        }

                        // convert seconds to radians
                        int diff_seconds = 0;

                        for (int i = 0; i < gi.ct.lim.lam; i++)
                        {
                            int cvs = row * gi.ct.lim.lam + (gi.ct.lim.lam - i - 1);

                            ct_tmp.cvs[cvs].phi = BitConverter.ToSingle(row_buf, (diff_seconds++) * sizeof(float)) * ((Proj.PI / 180.0) / 3600.0);
                            ct_tmp.cvs[cvs].lam = BitConverter.ToSingle(row_buf, (diff_seconds++) * sizeof(float)) * ((Proj.PI / 180.0) / 3600.0);
                            diff_seconds       += 2;                     // skip accuracy values
                        }
                    }

                    row_buf = null;

                    fid.Close();

                    gi.ct.cvs = ct_tmp.cvs;

                    return(true);
                }

                // --------------------------------------------------------------------
                //		GTX format.
                // --------------------------------------------------------------------
                if (gi.format == "gtx")
                {
                    int        words = gi.ct.lim.lam * gi.ct.lim.phi;
                    FileStream fid   = Proj.pj_open_lib(ctx, gi.filename, FileAccess.Read);
                    if (fid == null)
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    fid.Seek(gi.grid_offset, SeekOrigin.Begin);

                    byte[] buf;

                    try
                    {
                        buf        = new byte[words * sizeof(float)];
                        ct_tmp.cvs = new LP[words / 2];
                    }
                    catch
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(false);
                    }

                    try
                    {
                        if (fid.Read(buf, 0, words * sizeof(float)) != words * sizeof(float))
                        {
                            buf        = null;
                            ct_tmp.cvs = null;
                            return(false);
                        }
                    }
                    catch
                    {
                        buf        = null;
                        ct_tmp.cvs = null;
                        return(false);
                    }

                    if (IS_LSB)
                    {
                        swap_words(buf, 4, words);
                    }

                    for (int i = 0; i < words; i += 2)
                    {
                        ct_tmp.cvs[i / 2].phi = BitConverter.ToSingle(buf, i * sizeof(float));
                        ct_tmp.cvs[i / 2].lam = BitConverter.ToSingle(buf, (i + 1) * sizeof(float));
                    }

                    fid.Close();

                    gi.ct.cvs = ct_tmp.cvs;

                    return(true);
                }

                return(false);
            }             // lock(gridlock)
        }
示例#12
0
        public static int pj_apply_vgridshift(PJ defn, string listname, ref PJ_GRIDINFO[] gridlist_p, ref int gridlist_count_p, bool inverse, int point_count, int point_offset, double[] x, double[] y, double[] z)
        {
            if (gridlist_p == null)
            {
                gridlist_p = pj_gridlist_from_nadgrids(Proj.pj_get_ctx(defn), Proj.pj_param_s(defn.ctx, defn.parameters, listname), out gridlist_count_p);
                if (gridlist_p == null || gridlist_count_p == 0)
                {
                    return(defn.ctx.last_errno);
                }
            }

            if (gridlist_p == null || gridlist_count_p == 0)
            {
                Proj.pj_ctx_set_errno(defn.ctx, -38);
                return(-38);
            }

            PJ_GRIDINFO[] tables = gridlist_p;
            defn.ctx.last_errno = 0;

            for (int i = 0; i < point_count; i++)
            {
                int    io    = i * point_offset;
                double value = Libc.HUGE_VAL;

                LP input;
                input.phi = y[io];
                input.lam = x[io];

                // keep trying till we find a table that works
                for (int itable = 0; itable < gridlist_count_p; itable++)
                {
                    PJ_GRIDINFO gi = tables[itable];
                    CTABLE      ct = gi.ct;
                    double      grid_x, grid_y;
                    int         grid_ix, grid_iy;

                    // skip tables that don't match our point at all.
                    if (ct.ll.phi > input.phi || ct.ll.lam > input.lam || ct.ll.phi + (ct.lim.phi - 1) * ct.del.phi < input.phi || ct.ll.lam + (ct.lim.lam - 1) * ct.del.lam < input.lam)
                    {
                        continue;
                    }

                    // If we have child nodes, check to see if any of them apply.
                    while (gi.child != null)
                    {
                        PJ_GRIDINFO child = gi.child;

                        for (; child != null; child = child.next)
                        {
                            CTABLE ct1 = child.ct;

                            if (ct1.ll.phi > input.phi || ct1.ll.lam > input.lam || ct1.ll.phi + (ct1.lim.phi - 1) * ct1.del.phi < input.phi || ct1.ll.lam + (ct1.lim.lam - 1) * ct1.del.lam < input.lam)
                            {
                                continue;
                            }

                            break;
                        }

                        // If we didn't find a child then nothing more to do,
                        if (child == null)
                        {
                            break;
                        }

                        // otherwise use the child, first checking it's children.
                        gi = child;
                        ct = child.ct;
                    }

                    // load the grid shift info if we don't have it.
                    if (ct.cvs == null && !pj_gridinfo_load(Proj.pj_get_ctx(defn), gi))
                    {
                        Proj.pj_ctx_set_errno(defn.ctx, -38);
                        return(-38);
                    }

                    // Interpolation a location within the grid
                    grid_x  = (input.lam - ct.ll.lam) / ct.del.lam;
                    grid_y  = (input.phi - ct.ll.phi) / ct.del.phi;
                    grid_ix = (int)Math.Floor(grid_x);
                    grid_iy = (int)Math.Floor(grid_y);
                    grid_x -= grid_ix;
                    grid_y -= grid_iy;

                    LP cvs1 = ct.cvs[(grid_ix + grid_iy * ct.lim.lam) / 2];
                    LP cvs2 = ct.cvs[(grid_ix + (grid_iy + 1) * ct.lim.lam) / 2];
                    value = cvs1.lam * (1.0 - grid_x) * (1.0 - grid_y) + cvs1.phi * grid_x * (1.0 - grid_y) +
                            cvs2.lam * (1.0 - grid_x) * grid_y + cvs2.phi * grid_x * grid_y;

                    if (Math.Abs(value + 88.8888) < 0.0001)
                    {
                        value = Libc.HUGE_VAL;                                                  // nodata?
                    }
                    else
                    {
                        if (inverse)
                        {
                            z[io] -= value;
                        }
                        else
                        {
                            z[io] += value;
                        }
                    }

                    if (value != Libc.HUGE_VAL)
                    {
                        if (debug_count_apply_vgridshift++ < 20)
                        {
                            Proj.pj_log(defn.ctx, PJ_LOG.DEBUG_MINOR, "pj_apply_gridshift(): used {0}", ct.id);
                        }
                        break;
                    }
                }

                if (value == Libc.HUGE_VAL)
                {
                    Proj.pj_log(defn.ctx, PJ_LOG.DEBUG_MAJOR, "pj_apply_vgridshift(): failed to find a grid shift table for\n\t\t\tlocation ({0}dW,{1}dN)", x[io] * Proj.RAD_TO_DEG, y[io] * Proj.RAD_TO_DEG);
                    StringBuilder gridlist = new StringBuilder();
                    for (int itable = 0; itable < gridlist_count_p; itable++)
                    {
                        PJ_GRIDINFO gi = tables[itable];
                        if (itable == 0)
                        {
                            gridlist.AppendFormat("   tried: {0}", gi.gridname);
                        }
                        else
                        {
                            gridlist.AppendFormat(",{0}", gi.gridname);
                        }
                    }
                    Proj.pj_log(defn.ctx, PJ_LOG.DEBUG_MAJOR, "{0}", gridlist.ToString());

                    Proj.pj_ctx_set_errno(defn.ctx, (int)PJD_ERR.GRID_AREA);
                    return((int)PJD_ERR.GRID_AREA);
                }
            }

            return(0);
        }
示例#13
0
        // Determine nad table correction value
        public static LP nad_intr(LP t, CTABLE ct)
        {
            LP     val, frct;
            ILP    indx;
            double m00, m10, m01, m11;
            int    f00, f10, f01, f11;
            int    index;
            int    @in;

            t.lam   /= ct.del.lam;
            t.phi   /= ct.del.phi;
            indx.lam = (int)Math.Floor(t.lam);
            indx.phi = (int)Math.Floor(t.phi);
            frct.lam = t.lam - indx.lam;
            frct.phi = t.phi - indx.phi;
            val.lam  = val.phi = Libc.HUGE_VAL;

            if (indx.lam < 0)
            {
                if (indx.lam == -1 && frct.lam > 0.99999999999)
                {
                    indx.lam++;
                    frct.lam = 0.0;
                }
                else
                {
                    return(val);
                }
            }
            else
            {
                @in = indx.lam + 1;
                if (@in >= ct.lim.lam)
                {
                    if (@in == ct.lim.lam && frct.lam < 1e-11)
                    {
                        indx.lam--;
                        frct.lam = 1.0;
                    }
                    else
                    {
                        return(val);
                    }
                }
            }

            if (indx.phi < 0)
            {
                if (indx.phi == -1 && frct.phi > 0.99999999999)
                {
                    indx.phi++;
                    frct.phi = 0.0;
                }
                else
                {
                    return(val);
                }
            }
            else
            {
                @in = indx.phi + 1;
                if (@in >= ct.lim.phi)
                {
                    if (@in == ct.lim.phi && frct.phi < 1e-11)
                    {
                        indx.phi--;
                        frct.phi = 1.0;
                    }
                    else
                    {
                        return(val);
                    }
                }
            }

            index    = indx.phi * ct.lim.lam + indx.lam;
            f00      = index++;
            f10      = index;
            index   += ct.lim.lam;
            f11      = index--;
            f01      = index;
            m11      = m10 = frct.lam;
            m00      = m01 = 1.0 - frct.lam;
            m11     *= frct.phi;
            m01     *= frct.phi;
            frct.phi = 1.0 - frct.phi;
            m00     *= frct.phi;
            m10     *= frct.phi;

            val.lam = m00 * ct.cvs[f00].lam + m10 * ct.cvs[f10].lam + m01 * ct.cvs[f01].lam + m11 * ct.cvs[f11].lam;
            val.phi = m00 * ct.cvs[f00].phi + m10 * ct.cvs[f10].phi + m01 * ct.cvs[f01].phi + m11 * ct.cvs[f11].phi;

            return(val);
        }
示例#14
0
        static int debug_count_apply_gridshift_3 = 0;       // TODO
        public static int pj_apply_gridshift_3(projCtx ctx, PJ_GRIDINFO[] tables, int grid_count, bool inverse, int point_count, int point_offset, double[] x, double[] y, double[] z)
        {
            if (tables == null || grid_count == 0)
            {
                Proj.pj_ctx_set_errno(ctx, -38);
                return(-38);
            }

            ctx.last_errno = 0;

            for (int i = 0; i < point_count; i++)
            {
                long io = i * point_offset;
                LP   input, output;
                int  itable;

                input.phi  = y[io];
                input.lam  = x[io];
                output.phi = Libc.HUGE_VAL;
                output.lam = Libc.HUGE_VAL;

                // keep trying till we find a table that works
                for (itable = 0; itable < grid_count; itable++)
                {
                    PJ_GRIDINFO gi = tables[itable];
                    CTABLE      ct = gi.ct;

                    double epsilon = (Math.Abs(ct.del.phi) + Math.Abs(ct.del.lam)) / 10000.0;

                    // skip tables that don't match our point at all.
                    if (ct.ll.phi - epsilon > input.phi ||
                        ct.ll.lam - epsilon > input.lam ||
                        ct.ll.phi + (ct.lim.phi - 1) * ct.del.phi + epsilon < input.phi ||
                        ct.ll.lam + (ct.lim.lam - 1) * ct.del.lam + epsilon < input.lam)
                    {
                        continue;
                    }

                    // If we have child nodes, check to see if any of them apply.
                    while (gi.child != null)
                    {
                        PJ_GRIDINFO child = gi.child;

                        for (; child != null; child = child.next)
                        {
                            CTABLE ct1 = child.ct;
                            if (ct1.ll.phi - epsilon > input.phi ||
                                ct1.ll.lam - epsilon > input.lam ||
                                ct1.ll.phi + (ct1.lim.phi - 1) * ct1.del.phi + epsilon < input.phi ||
                                ct1.ll.lam + (ct1.lim.lam - 1) * ct1.del.lam + epsilon < input.lam)
                            {
                                continue;
                            }

                            break;
                        }

                        // If we didn't find a child then nothing more to do,
                        if (child == null)
                        {
                            break;
                        }

                        // otherwise use the child, first checking it's children.
                        gi = child;
                        ct = child.ct;
                    }

                    // load the grid shift info if we don't have it.
                    if (ct.cvs == null && !pj_gridinfo_load(ctx, gi))
                    {
                        Proj.pj_ctx_set_errno(ctx, -38);
                        return(-38);
                    }

                    output = nad_cvt(input, inverse, ct);
                    if (output.lam != Libc.HUGE_VAL)
                    {
                        if (debug_count_apply_gridshift_3++ < 20)
                        {
                            Proj.pj_log(ctx, PJ_LOG.DEBUG_MINOR, "pj_apply_gridshift(): used {0}", ct.id);
                        }
                        break;
                    }
                }

                if (output.lam == Libc.HUGE_VAL)
                {
                    if (ctx.debug_level >= PJ_LOG.DEBUG_MAJOR)
                    {
                        Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, "pj_apply_gridshift(): failed to find a grid shift table for\n\t\t\tlocation ({0}dW,{1}dN)", x[io] * Proj.RAD_TO_DEG, y[io] * Proj.RAD_TO_DEG);
                        for (itable = 0; itable < grid_count; itable++)
                        {
                            PJ_GRIDINFO gi = tables[itable];
                            if (itable == 0)
                            {
                                Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, "   tried: {0}", gi.gridname);
                            }
                            else
                            {
                                Proj.pj_log(ctx, PJ_LOG.DEBUG_MAJOR, ",{0}", gi.gridname);
                            }
                        }
                    }

                    // We don't actually have any machinery currently to set the
                    // following macro, so this is mostly kept here to make it clear
                    // how we ought to operate if we wanted to make it super clear
                    // that an error has occured when points are outside our available
                    // datum shift areas. But if this is on, we will find that "low
                    // value" points on the fringes of some datasets will completely
                    // fail causing lots of problems when it is more or less ok to
                    // just not apply a datum shift. So rather than deal with
                    // that we just fallback to no shift. (see also bug #45).
#if ERR_GRID_AREA_TRANSIENT_SEVERE
                    y[io] = Libc.HUGE_VAL;
                    x[io] = Libc.HUGE_VAL;
#else
                    // leave x/y unshifted.
#endif
                }
                else
                {
                    y[io] = output.phi;
                    x[io] = output.lam;
                }
            }

            return(0);
        }
示例#15
0
        public static LP nad_cvt(LP @in, bool inverse, CTABLE ct)
        {
            const int MAX_TRY = 9;

            if (@in.lam == Libc.HUGE_VAL)
            {
                return(@in);
            }

            // normalize input to ll origin
            LP tb = @in;

            tb.lam -= ct.ll.lam;
            tb.phi -= ct.ll.phi;
            tb.lam  = Proj.adjlon(tb.lam - Proj.PI) + Proj.PI;
            LP t = nad_intr(tb, ct);

            if (inverse)
            {
                LP  del, dif;
                int i = MAX_TRY;

                if (t.lam == Libc.HUGE_VAL)
                {
                    return(t);
                }
                t.lam = tb.lam + t.lam;
                t.phi = tb.phi - t.phi;

                do
                {
                    del = nad_intr(t, ct);

                    // 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.lam == Libc.HUGE_VAL)
                    {
#if DEBUG
                        Console.Error.WriteLine("Inverse grid shift iteration failed, presumably at grid edge.\nUsing first approximation.");
#endif
                        break;
                    }

                    t.lam -= dif.lam = t.lam - del.lam - tb.lam;
                    t.phi -= dif.phi = t.phi + del.phi - tb.phi;
                } while((i--) != 0 && Math.Abs(dif.lam) > TOL12 && Math.Abs(dif.phi) > TOL12);

                if (i < 0)
                {
#if DEBUG
                    Console.Error.WriteLine("Inverse grid shift iterator failed to converge.");
#endif
                    t.lam = t.phi = Libc.HUGE_VAL;
                    return(t);
                }

                @in.lam = Proj.adjlon(t.lam + ct.ll.lam);
                @in.phi = t.phi + ct.ll.phi;
            }
            else
            {
                if (t.lam == Libc.HUGE_VAL)
                {
                    @in = t;
                }
                else
                {
                    @in.lam -= t.lam;
                    @in.phi += t.phi;
                }
            }
            return(@in);
        }