#define PROJ_PARMS__ \
	int	noskew;
#define PJ_LIB__
# include	<projects.h>
PROJ_HEAD(bipc, "Bipolar conic of western hemisphere")
	"\n\tConic Sph.";
# define EPS	1e-10
# define EPS10	1e-10
# define ONEEPS 1.000000001
# define NITER	10
# define lamB	-.34894976726250681539
# define n	.63055844881274687180
# define F	1.89724742567461030582
# define Azab	.81650043674686363166
# define Azba	1.82261843856185925133
# define T	1.27246578267089012270
# define rhoc	1.20709121521568721927
# define cAzc	.69691523038678375519
# define sAzc	.71715351331143607555
# define C45	.70710678118654752469
# define S45	.70710678118654752410
# define C20	.93969262078590838411
# define S20	-.34202014332566873287
# define R110	1.91986217719376253360
# define R104	1.81514242207410275904
FORWARD(s_forward); /* spheroid */
	double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r;
	int tag;

	cphi = cos(lp.phi);
	sphi = sin(lp.phi);
	cdlam = cos(sdlam = lamB - lp.lam);
	sdlam = sin(sdlam);
	if (fabs(fabs(lp.phi) - HALFPI) < EPS10) {
		Az = lp.phi < 0. ? PI : 0.;
		tphi = HUGE_VAL;
	} else {
		tphi = sphi / cphi;
		Az = atan2(sdlam , C45 * (tphi - cdlam));
	}
	if( (tag = (Az > Azba)) ) {
		cdlam = cos(sdlam = lp.lam + R110);
		sdlam = sin(sdlam);
		z = S20 * sphi + C20 * cphi * cdlam;
		if (fabs(z) > 1.) {
			if (fabs(z) > ONEEPS) F_ERROR
			else z = z < 0. ? -1. : 1.;
		} else
			z = acos(z);
		if (tphi != HUGE_VAL)
			Az = atan2(sdlam, (C20 * tphi - S20 * cdlam));
		Av = Azab;
		xy.y = rhoc;
	} else {
		z = S45 * (sphi + cphi * cdlam);
		if (fabs(z) > 1.) {
			if (fabs(z) > ONEEPS) F_ERROR
			else z = z < 0. ? -1. : 1.;
		} else
			z = acos(z);
		Av = Azba;
		xy.y = -rhoc;
	}
	if (z < 0.) F_ERROR;
	r = F * (t = pow(tan(.5 * z), n));
	if ((al = .5 * (R104 - z)) < 0.) F_ERROR;
	al = (t + pow(al, n)) / T;
	if (fabs(al) > 1.) {
		if (fabs(al) > ONEEPS) F_ERROR
		else al = al < 0. ? -1. : 1.;
	} else
		al = acos(al);
	if (fabs(t = n * (Av - Az)) < al)
		r /= cos(al + (tag ? t : -t));
	xy.x = r * sin(t);
	xy.y += (tag ? -r : r) * cos(t);
	if (P->noskew) {
		t = xy.x;
		xy.x = -xy.x * cAzc - xy.y * sAzc; 
		xy.y = -xy.y * cAzc + t * sAzc; 
	}
	return (xy);
}
INVERSE(s_inverse); /* spheroid */
	double t, r, rp, rl, al, z, fAz, Az, s, c, Av;
	int neg, i;

	if (P->noskew) {
		t = xy.x;
		xy.x = -xy.x * cAzc + xy.y * sAzc; 
		xy.y = -xy.y * cAzc - t * sAzc; 
	}
	if( (neg = (xy.x < 0.)) ) {
		xy.y = rhoc - xy.y;
		s = S20;
		c = C20;
		Av = Azab;
	} else {
		xy.y += rhoc;
		s = S45;
		c = C45;
		Av = Azba;
	}
	rl = rp = r = hypot(xy.x, xy.y);
	fAz = fabs(Az = atan2(xy.x, xy.y));
	for (i = NITER; i ; --i) {
		z = 2. * atan(pow(r / F,1 / n));
		al = acos((pow(tan(.5 * z), n) +
		   pow(tan(.5 * (R104 - z)), n)) / T);
		if (fAz < al)
			r = rp * cos(al + (neg ? Az : -Az));
		if (fabs(rl - r) < EPS)
			break;
		rl = r;
	}
	if (! i) I_ERROR;
	Az = Av - Az / n;
	lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az));
	lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az));
	if (neg)
		lp.lam -= R110;
	else
		lp.lam = lamB - lp.lam;
	return (lp);
}
FREEUP; if (P) pj_dalloc(P); }
ENTRY0(bipc)
	P->noskew = pj_param(P->params, "bns").i;
	P->inv = s_inverse;
	P->fwd = s_forward;
	P->es = 0.;
ENDENTRY(P)
