Example #1
0
        static isea_geo isea_ctran(ref isea_geo np, isea_geo pt, double lon0)
        {
            isea_geo npt;

            np.lon += Math.PI;
            npt     = snyder_ctran(np, pt);
            np.lon -= Math.PI;

            npt.lon -= (Math.PI - lon0 + np.lon);

            // snyder is down tri 3, isea is along side of tri1 from vertex 0 to
            // vertex 1 these are 180 degrees apart
            npt.lon += Math.PI;

            // normalize longitude
            npt.lon = Math.IEEERemainder(npt.lon, 2 * Math.PI);
            while (npt.lon > Math.PI)
            {
                npt.lon -= 2 * Math.PI;
            }
            while (npt.lon < -Math.PI)
            {
                npt.lon += 2 * Math.PI;
            }

            return(npt);
        }
Example #2
0
        static double az_adjustment(int triangle)
        {
            double adj;

            isea_geo v = vertex[tri_v1[triangle]];
            isea_geo c = icostriangles[triangle];

            // TODO looks like the adjustment is always either 0 or 180
            // at least if you pick your vertex carefully
            adj = Math.Atan2(Math.Cos(v.lat) * Math.Sin(v.lon - c.lon),
                             Math.Cos(c.lat) * Math.Sin(v.lat) - Math.Sin(c.lat) * Math.Cos(v.lat) * Math.Cos(v.lon - c.lon));

            return(adj);
        }
Example #3
0
        static isea_pt isea_forward(isea_dgg g, isea_geo @in)
        {
            isea_pt @out, coord;

            int tri = isea_transform(ref g, @in, out @out);

            if (g.output == isea_address_form.ISEA_PLANE)
            {
                isea_tri_plane(tri, ref @out, g.radius);
                return(@out);
            }

            // convert to isea standard triangle size
            @out.x  = @out.x / g.radius * ISEA_SCALE;
            @out.y  = @out.y / g.radius * ISEA_SCALE;
            @out.x += 0.5;
            @out.y += 2.0 * .14433756729740644112;

            switch (g.output)
            {
            case isea_address_form.ISEA_PROJTRI:
                // nothing to do, already in projected triangle
                break;

            case isea_address_form.ISEA_VERTEX2DD:
                g.quad = isea_ptdd(tri, ref @out);
                break;

            case isea_address_form.ISEA_Q2DD:
                // Same as above, we just don't print as much
                g.quad = isea_ptdd(tri, ref @out);
                break;

            case isea_address_form.ISEA_Q2DI:
                g.quad = isea_ptdi(ref g, tri, @out, out coord);
                return(coord);

            case isea_address_form.ISEA_SEQNUM:
                isea_ptdi(ref g, tri, @out, out coord);
                // disn will set g->serial
                isea_disn(ref g, g.quad, coord);
                return(coord);

            case isea_address_form.ISEA_HEX:
                isea_hex(ref g, tri, @out, out coord);
                return(coord);
            }

            return(@out);
        }
Example #4
0
        static int isea_transform(ref isea_dgg g, isea_geo @in, out isea_pt @out)
        {
            isea_geo pole;

            pole.lat = g.o_lat;
            pole.lon = g.o_lon;

            isea_geo i = isea_ctran(ref pole, @in, g.o_az);

            int tri = isea_snyder_forward(i, out @out);

            @out.x    *= g.radius;
            @out.y    *= g.radius;
            g.triangle = tri;

            return(tri);
        }
Example #5
0
        // formula from Snyder, Map Projections: A working manual, p31 */
        //
        // old north pole at np in new coordinates
        // could be simplified a bit with fewer intermediates
        //
        // TODO take a result pointer
        static isea_geo snyder_ctran(isea_geo np, isea_geo pt)
        {
            double phi     = pt.lat;
            double lambda  = pt.lon;
            double alpha   = np.lat;
            double beta    = np.lon;
            double lambda0 = beta;

            double cos_p = Math.Cos(phi);
            double sin_a = Math.Sin(alpha);

            // mpawm 5-7
            double sin_phip = sin_a * Math.Sin(phi) - Math.Cos(alpha) * cos_p * Math.Cos(lambda - lambda0);

            // mpawm 5-8b

            // lambda prime minus beta
            // use the two argument form so we end up in the right quadrant
            double lp_b = Math.Atan2(cos_p * Math.Sin(lambda - lambda0), (sin_a * cos_p * Math.Cos(lambda - lambda0) + Math.Cos(alpha) * Math.Sin(phi)));

            double lambdap = lp_b + beta;

            // normalize longitude
            // TODO can we just do a modulus ?
            lambdap = Math.IEEERemainder(lambdap, 2 * Math.PI);
            while (lambdap > Math.PI)
            {
                lambdap -= 2 * Math.PI;
            }
            while (lambdap < -Math.PI)
            {
                lambdap += 2 * Math.PI;
            }

            double phip = Math.Asin(sin_phip);

            isea_geo npt;

            npt.lat = phip;
            npt.lon = lambdap;

            return(npt);
        }
Example #6
0
        // formula from Snyder, Map Projections: A working manual, p31 */
        //
        // old north pole at np in new coordinates
        // could be simplified a bit with fewer intermediates
        //
        // TODO take a result pointer
        static isea_geo snyder_ctran(isea_geo np, isea_geo pt)
        {
            double phi=pt.lat;
            double lambda=pt.lon;
            double alpha=np.lat;
            double beta=np.lon;
            double lambda0=beta;

            double cos_p=Math.Cos(phi);
            double sin_a=Math.Sin(alpha);

            // mpawm 5-7
            double sin_phip=sin_a*Math.Sin(phi)-Math.Cos(alpha)*cos_p*Math.Cos(lambda-lambda0);

            // mpawm 5-8b

            // lambda prime minus beta
            // use the two argument form so we end up in the right quadrant
            double lp_b=Math.Atan2(cos_p*Math.Sin(lambda-lambda0), (sin_a*cos_p*Math.Cos(lambda-lambda0)+Math.Cos(alpha)*Math.Sin(phi)));

            double lambdap=lp_b+beta;

            // normalize longitude
            // TODO can we just do a modulus ?
            lambdap=Math.IEEERemainder(lambdap, 2*Math.PI);
            while(lambdap>Math.PI) lambdap-=2*Math.PI;
            while(lambdap<-Math.PI) lambdap+=2*Math.PI;

            double phip=Math.Asin(sin_phip);

            isea_geo npt;

            npt.lat=phip;
            npt.lon=lambdap;

            return npt;
        }
Example #7
0
        static int isea_transform(ref isea_dgg g, isea_geo @in, out isea_pt @out)
        {
            isea_geo pole;
            pole.lat=g.o_lat;
            pole.lon=g.o_lon;

            isea_geo i=isea_ctran(ref pole, @in, g.o_az);

            int tri=isea_snyder_forward(i, out @out);
            @out.x*=g.radius;
            @out.y*=g.radius;
            g.triangle=tri;

            return tri;
        }
Example #8
0
        // coord needs to be in radians
        static int isea_snyder_forward(isea_geo ll, out isea_pt @out)
        {
            // TODO by locality of reference, start by trying the same triangle
            // as last time

            // TODO put these constants in as radians to begin with
            snyder_constants c=constants[(int)snyder_polyhedron.SNYDER_POLY_ICOSAHEDRON];

            // plane angle between radius vector to center and adjacent edge of
            // plane polygon
            double theta=c.theta*DEG2RAD;

            // spherical distance from center of polygon face to any of its
            // vertexes on the globe
            double g=c.g*DEG2RAD;

            // spherical angle between radius vector to center and adjacent edge
            // of spherical polygon on the globe
            double G=c.G*DEG2RAD;

            for(int i=1; i<=20; i++)
            {
                double z;
                isea_geo center;

                center=icostriangles[i];

                // step 1
                z=Math.Acos(Math.Sin(center.lat)*Math.Sin(ll.lat)+Math.Cos(center.lat)*Math.Cos(ll.lat)*Math.Cos(ll.lon-center.lon));

                // not on this triangle
                if(z>g+0.000005) continue; // TODO DBL_EPSILON

                double Az=sph_azimuth(center.lon, center.lat, ll.lon, ll.lat);

                // step 2

                // This calculates "some" vertex coordinate
                double az_offset=az_adjustment(i);

                Az-=az_offset;

                // TODO I don't know why we do this. It's not in snyder
                // maybe because we should have picked a better vertex
                if(Az<0.0) Az+=2.0*Math.PI;

                // adjust Az for the point to fall within the range of 0 to
                // 2(90 - theta) or 60 degrees for the hexagon, by
                // and therefore 120 degrees for the triangle
                // of the icosahedron
                // subtracting or adding multiples of 60 degrees to Az and
                // recording the amount of adjustment
                int Az_adjust_multiples=0; // how many multiples of 60 degrees we adjust the azimuth

                while(Az<0.0)
                {
                    Az+=DEG120;
                    Az_adjust_multiples--;
                }

                while(Az>DEG120+double.Epsilon)
                {
                    Az-=DEG120;
                    Az_adjust_multiples++;
                }

                // step 3
                double cot_theta=1.0/Math.Tan(theta);
                double tan_g=Math.Tan(g);	// TODO this is a constant

                // Calculate q from eq 9.
                // TODO cot_theta is cot(30)
                double q=Math.Atan2(tan_g, Math.Cos(Az)+Math.Sin(Az)*cot_theta);

                // not in this triangle
                if(z>q+0.000005) continue;
                // step 4

                // Apply equations 5-8 and 10-12 in order

                // eq 5
                // Rprime = 0.9449322893 * R;
                // R' in the paper is for the truncated
                double Rprime=0.91038328153090290025;

                // eq 6
                double H=Math.Acos(Math.Sin(Az)*Math.Sin(G)*Math.Cos(g)-Math.Cos(Az)*Math.Cos(G));

                // eq 7
                // Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180;
                double Ag=Az+G+H-DEG180;

                // eq 8
                double Azprime=Math.Atan2(2.0*Ag, Rprime*Rprime*tan_g*tan_g-2.0*Ag*cot_theta);

                // eq 10
                // cot(theta) = 1.73205080756887729355
                double dprime=Rprime*tan_g/(Math.Cos(Azprime)+Math.Sin(Azprime)*cot_theta);

                // eq 11
                double f=dprime/(2.0*Rprime*Math.Sin(q/2.0));

                // eq 12
                double rho=2.0*Rprime*f*Math.Sin(z/2.0);

                // add back the same 60 degree multiple adjustment from step
                // 2 to Azprime
                Azprime+=DEG120*Az_adjust_multiples;

                // calculate rectangular coordinates
                double x=rho*Math.Sin(Azprime);
                double y=rho*Math.Cos(Azprime);

                // TODO
                // translate coordinates to the origin for the particular
                // hexagon on the flattened polyhedral map plot
                @out.x=x;
                @out.y=y;

                return i;
            }

            // should be impossible, this implies that the coordinate is not on
            // any triangle

            //fprintf(stderr, "impossible transform: %f %f is not on any triangle\n",
            //    ll.lon*RAD2DEG, ll.lat*RAD2DEG);

            throw new Exception();
        }
Example #9
0
        static isea_pt isea_forward(isea_dgg g, isea_geo @in)
        {
            isea_pt @out, coord;

            int tri=isea_transform(ref g, @in, out @out);

            if(g.output==isea_address_form.ISEA_PLANE)
            {
                isea_tri_plane(tri, ref @out, g.radius);
                return @out;
            }

            // convert to isea standard triangle size
            @[email protected]/g.radius*ISEA_SCALE;
            @[email protected]/g.radius*ISEA_SCALE;
            @out.x+=0.5;
            @out.y+=2.0*.14433756729740644112;

            switch(g.output)
            {
                case isea_address_form.ISEA_PROJTRI:
                    // nothing to do, already in projected triangle
                    break;
                case isea_address_form.ISEA_VERTEX2DD:
                    g.quad=isea_ptdd(tri, ref @out);
                    break;
                case isea_address_form.ISEA_Q2DD:
                    // Same as above, we just don't print as much
                    g.quad=isea_ptdd(tri, ref @out);
                    break;
                case isea_address_form.ISEA_Q2DI:
                    g.quad=isea_ptdi(ref g, tri, @out, out coord);
                    return coord;
                case isea_address_form.ISEA_SEQNUM:
                    isea_ptdi(ref g, tri, @out, out coord);
                    // disn will set g->serial
                    isea_disn(ref g, g.quad, coord);
                    return coord;
                case isea_address_form.ISEA_HEX:
                    isea_hex(ref g, tri, @out, out coord);
                    return coord;
            }

            return @out;
        }
Example #10
0
        static isea_geo isea_ctran(ref isea_geo np, isea_geo pt, double lon0)
        {
            isea_geo npt;

            np.lon+=Math.PI;
            npt=snyder_ctran(np, pt);
            np.lon-=Math.PI;

            npt.lon-=(Math.PI-lon0+np.lon);

            // snyder is down tri 3, isea is along side of tri1 from vertex 0 to
            // vertex 1 these are 180 degrees apart
            npt.lon+=Math.PI;

            // normalize longitude
            npt.lon=Math.IEEERemainder(npt.lon, 2*Math.PI);
            while(npt.lon>Math.PI) npt.lon-=2*Math.PI;
            while(npt.lon<-Math.PI) npt.lon+=2*Math.PI;

            return npt;
        }
Example #11
0
        // coord needs to be in radians
        static int isea_snyder_forward(isea_geo ll, out isea_pt @out)
        {
            // TODO by locality of reference, start by trying the same triangle
            // as last time

            // TODO put these constants in as radians to begin with
            snyder_constants c = constants[(int)snyder_polyhedron.SNYDER_POLY_ICOSAHEDRON];

            // plane angle between radius vector to center and adjacent edge of
            // plane polygon
            double theta = c.theta * DEG2RAD;

            // spherical distance from center of polygon face to any of its
            // vertexes on the globe
            double g = c.g * DEG2RAD;

            // spherical angle between radius vector to center and adjacent edge
            // of spherical polygon on the globe
            double G = c.G * DEG2RAD;

            for (int i = 1; i <= 20; i++)
            {
                double   z;
                isea_geo center;

                center = icostriangles[i];

                // step 1
                z = Math.Acos(Math.Sin(center.lat) * Math.Sin(ll.lat) + Math.Cos(center.lat) * Math.Cos(ll.lat) * Math.Cos(ll.lon - center.lon));

                // not on this triangle
                if (z > g + 0.000005)
                {
                    continue;                              // TODO DBL_EPSILON
                }
                double Az = sph_azimuth(center.lon, center.lat, ll.lon, ll.lat);

                // step 2

                // This calculates "some" vertex coordinate
                double az_offset = az_adjustment(i);

                Az -= az_offset;

                // TODO I don't know why we do this. It's not in snyder
                // maybe because we should have picked a better vertex
                if (Az < 0.0)
                {
                    Az += 2.0 * Math.PI;
                }

                // adjust Az for the point to fall within the range of 0 to
                // 2(90 - theta) or 60 degrees for the hexagon, by
                // and therefore 120 degrees for the triangle
                // of the icosahedron
                // subtracting or adding multiples of 60 degrees to Az and
                // recording the amount of adjustment
                int Az_adjust_multiples = 0;               // how many multiples of 60 degrees we adjust the azimuth

                while (Az < 0.0)
                {
                    Az += DEG120;
                    Az_adjust_multiples--;
                }

                while (Az > DEG120 + double.Epsilon)
                {
                    Az -= DEG120;
                    Az_adjust_multiples++;
                }

                // step 3
                double cot_theta = 1.0 / Math.Tan(theta);
                double tan_g     = Math.Tan(g);                 // TODO this is a constant

                // Calculate q from eq 9.
                // TODO cot_theta is cot(30)
                double q = Math.Atan2(tan_g, Math.Cos(Az) + Math.Sin(Az) * cot_theta);

                // not in this triangle
                if (z > q + 0.000005)
                {
                    continue;
                }
                // step 4

                // Apply equations 5-8 and 10-12 in order

                // eq 5
                // Rprime = 0.9449322893 * R;
                // R' in the paper is for the truncated
                double Rprime = 0.91038328153090290025;

                // eq 6
                double H = Math.Acos(Math.Sin(Az) * Math.Sin(G) * Math.Cos(g) - Math.Cos(Az) * Math.Cos(G));

                // eq 7
                // Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180;
                double Ag = Az + G + H - DEG180;

                // eq 8
                double Azprime = Math.Atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta);

                // eq 10
                // cot(theta) = 1.73205080756887729355
                double dprime = Rprime * tan_g / (Math.Cos(Azprime) + Math.Sin(Azprime) * cot_theta);

                // eq 11
                double f = dprime / (2.0 * Rprime * Math.Sin(q / 2.0));

                // eq 12
                double rho = 2.0 * Rprime * f * Math.Sin(z / 2.0);

                // add back the same 60 degree multiple adjustment from step
                // 2 to Azprime
                Azprime += DEG120 * Az_adjust_multiples;

                // calculate rectangular coordinates
                double x = rho * Math.Sin(Azprime);
                double y = rho * Math.Cos(Azprime);

                // TODO
                // translate coordinates to the origin for the particular
                // hexagon on the flattened polyhedral map plot
                @out.x = x;
                @out.y = y;

                return(i);
            }

            // should be impossible, this implies that the coordinate is not on
            // any triangle

            //fprintf(stderr, "impossible transform: %f %f is not on any triangle\n",
            //    ll.lon*RAD2DEG, ll.lat*RAD2DEG);

            throw new Exception();
        }