LPZ inverse3d(XYZ xyz)
		{
			LPZ lpz;
			lpz.lam = lpz.phi = lpz.z = 0;

			// Local lat, lon using radius
			double pxyz0 = xyz.y * a / rcurv;
			double pxyz1 = xyz.x * a / rcurv;
			double pxyz2 = xyz.z;

			double temp0, temp1, temp2;
			if (sph.pj_Convert_Geodetic_To_Geocentric(pxyz0, pxyz1, pxyz2, out temp0, out temp1, out temp2) != 0) { Proj.pj_ctx_set_errno(ctx, -20); return lpz; }

			// Apply rotation
			pxyz0 = transMat[0] * temp0 + transMat[1] * temp1 + transMat[2] * temp2;
			pxyz1 = transMat[3] * temp0 + transMat[4] * temp1 + transMat[5] * temp2;
			pxyz2 = transMat[6] * temp0 + transMat[7] * temp1 + transMat[8] * temp2;

			// Apply offset
			pxyz0 += xyzoff[0];
			pxyz1 += xyzoff[1];
			pxyz2 += xyzoff[2];

			// Convert geocentric coordinates to lat lon
			elp_0.pj_Convert_Geocentric_To_Geodetic(pxyz0, pxyz1, pxyz2, out temp0, out temp1, out temp2);

			lpz.lam = temp1;
			lpz.phi = temp0;
			lpz.z = temp2;

			//printf("INVERSE: \n");
			//printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z);
			//printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z);
			return lpz;
		}
		// general inverse projection

		// inverse projection entry
		public static LPZ pj_inv3d(XYZ xyz, PJ P)
		{
			LPZ lpz;

			// can't do as much preliminary checking as with forward
			if (xyz.x == Libc.HUGE_VAL || xyz.y == Libc.HUGE_VAL || xyz.z == Libc.HUGE_VAL)
			{
				lpz.lam = lpz.phi = lpz.z = Libc.HUGE_VAL;
				pj_ctx_set_errno(P.ctx, -15);
				return lpz;
			}

			Libc.errno = pj_errno = 0;
			P.ctx.last_errno = 0;

			xyz.x = (xyz.x * P.to_meter - P.x0) * P.ra; // descale and de-offset
			xyz.y = (xyz.y * P.to_meter - P.y0) * P.ra;
			// z is not scaled since that is handled by vto_meter before we get here

			// Check for NULL pointer
			if (P.inv3d != null)
			{
				lpz = P.inv3d(xyz); // inverse project
				if (P.ctx.last_errno != 0) lpz.lam = lpz.phi = lpz.z = Libc.HUGE_VAL;
				else
				{
					lpz.lam += P.lam0; // reduce from del lp.lam
					if (!P.over) lpz.lam = adjlon(lpz.lam); // adjust longitude to CM

					// This maybe redundant and never used
					if (P.geoc && Math.Abs(Math.Abs(lpz.phi) - HALFPI) > EPS12) lpz.phi = Math.Atan(P.one_es * Math.Tan(lpz.phi));
				}
			}
			else
			{
				lpz.lam = lpz.phi = lpz.z = Libc.HUGE_VAL;
			}

			return lpz;
		}