xref: /plan9/sys/src/cmd/map/libmap/tetra.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
1*59cc4ca5SDavid du Colombier #include <u.h>
2*59cc4ca5SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "map.h"
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier /*
63e12c5d1SDavid du Colombier  *	conformal map of earth onto tetrahedron
73e12c5d1SDavid du Colombier  *	the stages of mapping are
83e12c5d1SDavid du Colombier  *	(a) stereo projection of tetrahedral face onto
93e12c5d1SDavid du Colombier  *	    isosceles curvilinear triangle with 3 120-degree
103e12c5d1SDavid du Colombier  *	    angles and one straight side
113e12c5d1SDavid du Colombier  *	(b) map of this triangle onto half plane cut along
123e12c5d1SDavid du Colombier  *	    3 rays from the roots of unity to infinity
133e12c5d1SDavid du Colombier  *		formula (z^4+2*3^.5*z^2-1)/(z^4-2*3^.5*z^2-1)
143e12c5d1SDavid du Colombier  *	(c) do 3 times for  each sector of plane:
153e12c5d1SDavid du Colombier  *	    map of |arg z|<=pi/6, cut along z>1 into
163e12c5d1SDavid du Colombier  *	    triangle |arg z|<=pi/6, Re z<=const,
173e12c5d1SDavid du Colombier  *	    with upper side of cut going into upper half of
183e12c5d1SDavid du Colombier  *	    of vertical side of triangle and lowere into lower
193e12c5d1SDavid du Colombier  *		formula int from 0 to z dz/sqrt(1-z^3)
203e12c5d1SDavid du Colombier  *
213e12c5d1SDavid du Colombier  *	int from u to 1 3^.25*du/sqrt(1-u^3) =
223e12c5d1SDavid du Colombier 		F(acos((rt3-1+u)/(rt3+1-u)),sqrt(1/2+rt3/4))
233e12c5d1SDavid du Colombier  *	int from 1 to u 3^.25*du/sqrt(u^3-1) =
243e12c5d1SDavid du Colombier  *		F(acos((rt3+1-u)/(rt3-1+u)),sqrt(1/2-rt3/4))
253e12c5d1SDavid du Colombier  *	this latter formula extends analytically down to
263e12c5d1SDavid du Colombier  *	u=0 and is the basis of this routine, with the
273e12c5d1SDavid du Colombier  *	argument of complex elliptic integral elco2
283e12c5d1SDavid du Colombier  *	being tan(acos...)
293e12c5d1SDavid du Colombier  *	the formula F(pi-x,k) = 2*F(pi/2,k)-F(x,k) is
303e12c5d1SDavid du Colombier  *	used to cross over into the region where Re(acos...)>pi/2
313e12c5d1SDavid du Colombier  *		f0 and fpi are suitably scaled complete integrals
323e12c5d1SDavid du Colombier */
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier #define TFUZZ 0.00001
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier static struct place tpole[4];	/* point of tangency of tetrahedron face*/
37219b2ee8SDavid du Colombier static double tpoleinit[4][2] = {
383e12c5d1SDavid du Colombier 	1.,	0.,
393e12c5d1SDavid du Colombier 	1.,	180.,
403e12c5d1SDavid du Colombier 	-1.,	90.,
413e12c5d1SDavid du Colombier 	-1.,	-90.
423e12c5d1SDavid du Colombier };
433e12c5d1SDavid du Colombier static struct tproj {
44219b2ee8SDavid du Colombier 	double tlat,tlon;	/* center of stereo projection*/
45219b2ee8SDavid du Colombier 	double ttwist;		/* rotatn before stereo*/
46219b2ee8SDavid du Colombier 	double trot;		/*rotate after projection*/
473e12c5d1SDavid du Colombier 	struct place projpl;	/*same as tlat,tlon*/
483e12c5d1SDavid du Colombier 	struct coord projtw;	/*same as ttwist*/
493e12c5d1SDavid du Colombier 	struct coord postrot;	/*same as trot*/
503e12c5d1SDavid du Colombier } tproj[4][4] = {
513e12c5d1SDavid du Colombier {/*00*/	{0.},
523e12c5d1SDavid du Colombier  /*01*/	{90.,	0.,	90.,	-90.},
533e12c5d1SDavid du Colombier  /*02*/	{0.,	45.,	-45.,	150.},
543e12c5d1SDavid du Colombier  /*03*/	{0.,	-45.,	-135.,	30.}
553e12c5d1SDavid du Colombier },
563e12c5d1SDavid du Colombier {/*10*/	{90.,	0.,	-90.,	90.},
573e12c5d1SDavid du Colombier  /*11*/ {0.},
583e12c5d1SDavid du Colombier  /*12*/ {0.,	135.,	-135.,	-150.},
593e12c5d1SDavid du Colombier  /*13*/	{0.,	-135.,	-45.,	-30.}
603e12c5d1SDavid du Colombier },
613e12c5d1SDavid du Colombier {/*20*/	{0.,	45.,	135.,	-30.},
623e12c5d1SDavid du Colombier  /*21*/	{0.,	135.,	45.,	-150.},
633e12c5d1SDavid du Colombier  /*22*/	{0.},
643e12c5d1SDavid du Colombier  /*23*/	{-90.,	0.,	180.,	90.}
653e12c5d1SDavid du Colombier },
663e12c5d1SDavid du Colombier {/*30*/	{0.,	-45.,	45.,	-150.},
673e12c5d1SDavid du Colombier  /*31*/ {0.,	-135.,	135.,	-30.},
683e12c5d1SDavid du Colombier  /*32*/	{-90.,	0.,	0.,	90.},
693e12c5d1SDavid du Colombier  /*33*/ {0.}
703e12c5d1SDavid du Colombier }};
71219b2ee8SDavid du Colombier static double tx[4] = {	/*where to move facet after final rotation*/
723e12c5d1SDavid du Colombier 	0.,	0.,	-1.,	1.	/*-1,1 to be sqrt(3)*/
733e12c5d1SDavid du Colombier };
74219b2ee8SDavid du Colombier static double ty[4] = {
753e12c5d1SDavid du Colombier 	0.,	2.,	-1.,	-1.
763e12c5d1SDavid du Colombier };
773e12c5d1SDavid du Colombier static double root3;
78219b2ee8SDavid du Colombier static double rt3inv;
793e12c5d1SDavid du Colombier static double two_rt3;
803e12c5d1SDavid du Colombier static double tkc,tk,tcon;
81219b2ee8SDavid du Colombier static double f0r,f0i,fpir,fpii;
823e12c5d1SDavid du Colombier 
833e12c5d1SDavid du Colombier static void
twhichp(struct place * g,int * p,int * q)843e12c5d1SDavid du Colombier twhichp(struct place *g, int *p, int *q)
853e12c5d1SDavid du Colombier {
863e12c5d1SDavid du Colombier 	int i,j,k;
87219b2ee8SDavid du Colombier 	double cosdist[4];
883e12c5d1SDavid du Colombier 	struct place *tp;
893e12c5d1SDavid du Colombier 	for(i=0;i<4;i++) {
903e12c5d1SDavid du Colombier 		tp = &tpole[i];
913e12c5d1SDavid du Colombier 		cosdist[i] = g->nlat.s*tp->nlat.s +
923e12c5d1SDavid du Colombier 			  g->nlat.c*tp->nlat.c*(
933e12c5d1SDavid du Colombier 			  g->wlon.s*tp->wlon.s +
943e12c5d1SDavid du Colombier 			  g->wlon.c*tp->wlon.c);
953e12c5d1SDavid du Colombier 	}
963e12c5d1SDavid du Colombier 	j = 0;
973e12c5d1SDavid du Colombier 	for(i=1;i<4;i++)
983e12c5d1SDavid du Colombier 		if(cosdist[i] > cosdist[j])
993e12c5d1SDavid du Colombier 			j = i;
1003e12c5d1SDavid du Colombier 	*p = j;
1013e12c5d1SDavid du Colombier 	k = j==0?1:0;
1023e12c5d1SDavid du Colombier 	for(i=0;i<4;i++)
1033e12c5d1SDavid du Colombier 		if(i!=j&&cosdist[i]>cosdist[k])
1043e12c5d1SDavid du Colombier 			k = i;
1053e12c5d1SDavid du Colombier 	*q = k;
1063e12c5d1SDavid du Colombier }
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier int
Xtetra(struct place * place,double * x,double * y)109219b2ee8SDavid du Colombier Xtetra(struct place *place, double *x, double *y)
1103e12c5d1SDavid du Colombier {
1113e12c5d1SDavid du Colombier 	int i,j;
1123e12c5d1SDavid du Colombier 	struct place pl;
1133e12c5d1SDavid du Colombier 	register struct tproj *tpp;
114219b2ee8SDavid du Colombier 	double vr, vi;
1153e12c5d1SDavid du Colombier 	double br, bi;
1163e12c5d1SDavid du Colombier 	double zr,zi,z2r,z2i,z4r,z4i,sr,si,tr,ti;
1173e12c5d1SDavid du Colombier 	twhichp(place,&i,&j);
1183e12c5d1SDavid du Colombier 	copyplace(place,&pl);
1193e12c5d1SDavid du Colombier 	norm(&pl,&tproj[i][j].projpl,&tproj[i][j].projtw);
1203e12c5d1SDavid du Colombier 	Xstereographic(&pl,&vr,&vi);
1213e12c5d1SDavid du Colombier 	zr = vr/2;
1223e12c5d1SDavid du Colombier 	zi = vi/2;
1233e12c5d1SDavid du Colombier 	if(zr<=TFUZZ)
1243e12c5d1SDavid du Colombier 		zr = TFUZZ;
1253e12c5d1SDavid du Colombier 	csq(zr,zi,&z2r,&z2i);
1263e12c5d1SDavid du Colombier 	csq(z2r,z2i,&z4r,&z4i);
1273e12c5d1SDavid du Colombier 	z2r *= two_rt3;
1283e12c5d1SDavid du Colombier 	z2i *= two_rt3;
1293e12c5d1SDavid du Colombier 	cdiv(z4r+z2r-1,z4i+z2i,z4r-z2r-1,z4i-z2i,&sr,&si);
1303e12c5d1SDavid du Colombier 	csqrt(sr-1,si,&tr,&ti);
1313e12c5d1SDavid du Colombier 	cdiv(tcon*tr,tcon*ti,root3+1-sr,-si,&br,&bi);
1323e12c5d1SDavid du Colombier 	if(br<0) {
1333e12c5d1SDavid du Colombier 		br = -br;
1343e12c5d1SDavid du Colombier 		bi = -bi;
1353e12c5d1SDavid du Colombier 		if(!elco2(br,bi,tk,1.,1.,&vr,&vi))
1363e12c5d1SDavid du Colombier 			return 0;
1373e12c5d1SDavid du Colombier 		vr = fpir - vr;
1383e12c5d1SDavid du Colombier 		vi = fpii - vi;
1393e12c5d1SDavid du Colombier 	} else
1403e12c5d1SDavid du Colombier 		if(!elco2(br,bi,tk,1.,1.,&vr,&vi))
1413e12c5d1SDavid du Colombier 			return 0;
1423e12c5d1SDavid du Colombier 	if(si>=0) {
1433e12c5d1SDavid du Colombier 		tr = f0r - vi;
1443e12c5d1SDavid du Colombier 		ti = f0i + vr;
1453e12c5d1SDavid du Colombier 	} else {
1463e12c5d1SDavid du Colombier 		tr = f0r + vi;
1473e12c5d1SDavid du Colombier 		ti = f0i - vr;
1483e12c5d1SDavid du Colombier 	}
1493e12c5d1SDavid du Colombier 	tpp = &tproj[i][j];
1503e12c5d1SDavid du Colombier 	*x = tr*tpp->postrot.c +
1513e12c5d1SDavid du Colombier 	     ti*tpp->postrot.s + tx[i];
1523e12c5d1SDavid du Colombier 	*y = ti*tpp->postrot.c -
1533e12c5d1SDavid du Colombier 	     tr*tpp->postrot.s + ty[i];
1543e12c5d1SDavid du Colombier 	return(1);
1553e12c5d1SDavid du Colombier }
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier int
tetracut(struct place * g,struct place * og,double * cutlon)158219b2ee8SDavid du Colombier tetracut(struct place *g, struct place *og, double *cutlon)
1593e12c5d1SDavid du Colombier {
1603e12c5d1SDavid du Colombier 	int i,j,k;
1613e12c5d1SDavid du Colombier 	if((g->nlat.s<=-rt3inv&&og->nlat.s<=-rt3inv) &&
1623e12c5d1SDavid du Colombier 	   (ckcut(g,og,*cutlon=0.)==2||ckcut(g,og,*cutlon=PI)==2))
1633e12c5d1SDavid du Colombier 		return(2);
1643e12c5d1SDavid du Colombier 	twhichp(g,&i,&k);
1653e12c5d1SDavid du Colombier 	twhichp(og,&j,&k);
1663e12c5d1SDavid du Colombier 	if(i==j||i==0||j==0)
1673e12c5d1SDavid du Colombier 		return(1);
1683e12c5d1SDavid du Colombier 	return(0);
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier proj
tetra(void)1723e12c5d1SDavid du Colombier tetra(void)
1733e12c5d1SDavid du Colombier {
1743e12c5d1SDavid du Colombier 	register i;
1753e12c5d1SDavid du Colombier 	int j;
1763e12c5d1SDavid du Colombier 	register struct place *tp;
1773e12c5d1SDavid du Colombier 	register struct tproj *tpp;
178219b2ee8SDavid du Colombier 	double t;
1793e12c5d1SDavid du Colombier 	root3 = sqrt(3.);
1803e12c5d1SDavid du Colombier 	rt3inv = 1/root3;
1813e12c5d1SDavid du Colombier 	two_rt3 = 2*root3;
1823e12c5d1SDavid du Colombier 	tkc = sqrt(.5-.25*root3);
1833e12c5d1SDavid du Colombier 	tk = sqrt(.5+.25*root3);
1843e12c5d1SDavid du Colombier 	tcon = 2*sqrt(root3);
1853e12c5d1SDavid du Colombier 	elco2(tcon/(root3-1),0.,tkc,1.,1.,&f0r,&f0i);
1863e12c5d1SDavid du Colombier 	elco2(1.e15,0.,tk,1.,1.,&fpir,&fpii);
1873e12c5d1SDavid du Colombier 	fpir *= 2;
1883e12c5d1SDavid du Colombier 	fpii *= 2;
1893e12c5d1SDavid du Colombier 	for(i=0;i<4;i++) {
1903e12c5d1SDavid du Colombier 		tx[i] *= f0r*root3;
1913e12c5d1SDavid du Colombier 		ty[i] *= f0r;
1923e12c5d1SDavid du Colombier 		tp = &tpole[i];
1933e12c5d1SDavid du Colombier 		t = tp->nlat.s = tpoleinit[i][0]/root3;
1943e12c5d1SDavid du Colombier 		tp->nlat.c = sqrt(1 - t*t);
1953e12c5d1SDavid du Colombier 		tp->nlat.l = atan2(tp->nlat.s,tp->nlat.c);
1963e12c5d1SDavid du Colombier 		deg2rad(tpoleinit[i][1],&tp->wlon);
1973e12c5d1SDavid du Colombier 		for(j=0;j<4;j++) {
1983e12c5d1SDavid du Colombier 			tpp = &tproj[i][j];
1993e12c5d1SDavid du Colombier 			latlon(tpp->tlat,tpp->tlon,&tpp->projpl);
2003e12c5d1SDavid du Colombier 			deg2rad(tpp->ttwist,&tpp->projtw);
2013e12c5d1SDavid du Colombier 			deg2rad(tpp->trot,&tpp->postrot);
2023e12c5d1SDavid du Colombier 		}
2033e12c5d1SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier 	return(Xtetra);
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier 
207