예제 #1
0
        public LP[] cvs;                // conversion matrix

        public CTABLE Clone()
        {
            CTABLE ret = new CTABLE();

            ret.id  = id;
            ret.ll  = ll;
            ret.del = del;
            ret.lim = lim;
            ret.cvs = cvs;
            return(ret);
        }
예제 #2
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;
        }
예제 #3
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;
        }
예제 #4
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;
        }
예제 #5
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;
            }
        }
예제 #6
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;
 }
예제 #7
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;
        }
예제 #8
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;
            }
        }
예제 #9
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;
            }
        }
예제 #10
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;
        }
예제 #11
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;
        }