boolean getPrincipalAxes(int atomIndex, Vector3f z, Vector3f x, String lcaoTypeRaw, boolean hybridizationCompatible) {
		String lcaoType = (lcaoTypeRaw.length() > 0 && lcaoTypeRaw.charAt(0) == '-' ? lcaoTypeRaw.substring(1)
				: lcaoTypeRaw);
		Atom atom = atoms[atomIndex];
		hybridization = "";
		z.set(0, 0, 0);
		x.set(0, 0, 0);
		Atom atom1 = atom;
		Atom atom2 = atom;
		int nBonds = 0;
		float _180 = (float) Math.PI * 0.95f;
		Vector3f n = new Vector3f();
		Vector3f x2 = new Vector3f();
		Vector3f x3 = new Vector3f(3.14159f, 2.71828f, 1.41421f);
		Vector3f x4 = new Vector3f();
		Vector3f y1 = new Vector3f();
		Vector3f y2 = new Vector3f();
		if (atom.bonds != null)
			for (int i = atom.bonds.length; --i >= 0;)
				if (atom.bonds[i].isCovalent()) {
					++nBonds;
					atom1 = atom.bonds[i].getOtherAtom(atom);
					n.sub(atom, atom1);
					n.normalize();
					z.add(n);
					switch (nBonds) {
					case 1:
						x.set(n);
						atom2 = atom1;
						break;
					case 2:
						x2.set(n);
						break;
					case 3:
						x3.set(n);
						x4.set(-z.x, -z.y, -z.z);
						break;
					case 4:
						x4.set(n);
						break;
					default:
						i = -1;
					}
				}
		switch (nBonds) {
		case 0:
			z.set(0, 0, 1);
			x.set(1, 0, 0);
			break;
		case 1:
			if (lcaoType.indexOf("sp3") == 0) { // align z as sp3 orbital
				hybridization = "sp3";
				x.cross(x3, z);
				y1.cross(z, x);
				x.normalize();
				y1.normalize();
				y2.set(x);
				z.normalize();
				x.scaleAdd(2.828f, x, z); // 2*sqrt(2)
				if (!lcaoType.equals("sp3a") && !lcaoType.equals("sp3")) {
					x.normalize();
					AxisAngle4f a = new AxisAngle4f(z.x, z.y, z.z, (lcaoType.equals("sp3b") ? 1 : -1) * 2.09439507f); // PI*2/3
					Matrix3f m = new Matrix3f();
					m.setIdentity();
					m.set(a);
					m.transform(x);
				}
				z.set(x);
				x.cross(y1, z);
				break;
			}
			hybridization = "sp";
			if (atom1.getCovalentBondCount() == 3) {
				// special case, for example R2C=O oxygen
				getPrincipalAxes(atom1.atomIndex, z, x3, lcaoType, false);
				x3.set(x);
				if (lcaoType.indexOf("sp2") == 0) { // align z as sp2 orbital
					hybridization = "sp2";
					z.scale(-1);
				}
			}
			x.cross(x3, z);
			break;
		case 2:
			if (z.length() < 0.1) {
				// linear A--X--B
				hybridization = "sp";
				if (!lcaoType.equals("pz")) {
					if (atom1.getCovalentBondCount() != 3)
						atom1 = atom2;
					if (atom1.getCovalentBondCount() == 3) {
						// special case, for example R2C=C=CR2 central carbon
						getPrincipalAxes(atom1.atomIndex, x, z, "pz", false);
						if (lcaoType.equals("px"))
							x.scale(-1);
						z.set(x2);
						break;
					}
				}
				z.set(x);
				x.cross(x3, z);
				break;
			}
			// bent A--X--B
			hybridization = (lcaoType.indexOf("sp3") == 0 ? "sp3" : "sp2");
			x3.cross(z, x);
			if (lcaoType.indexOf("sp") == 0) { // align z as sp2 orbital
				if (lcaoType.equals("sp2a") || lcaoType.equals("sp2b")) {
					z.set(lcaoType.indexOf("b") >= 0 ? x2 : x);
					z.scale(-1);
				}
				x.cross(z, x3);
				break;
			}
			if (lcaoType.indexOf("lp") == 0) { // align z as lone pair
				hybridization = "lp"; // any is OK
				x3.normalize();
				z.normalize();
				y1.scaleAdd(1.2f, x3, z);
				y2.scaleAdd(-1.2f, x3, z);
				z.set(lcaoType.indexOf("b") >= 0 ? y2 : y1);
				x.cross(z, x3);
				break;
			}
			hybridization = lcaoType;
			// align z as p orbital
			x.cross(z, x3);
			z.set(x3);
			if (z.z < 0) {
				z.set(-z.x, -z.y, -z.z);
				x.set(-x.x, -x.y, -x.z);
			}
			break;
		default:
			// 3 or 4 bonds
			if (x.angle(x2) < _180)
				y1.cross(x, x2);
			else y1.cross(x, x3);
			y1.normalize();
			if (x2.angle(x3) < _180)
				y2.cross(x2, x3);
			else y2.cross(x, x3);
			y2.normalize();
			if (Math.abs(y2.dot(y1)) < 0.95f) {
				hybridization = "sp3";
				if (lcaoType.indexOf("sp") == 0) { // align z as sp3 orbital
					z.set(lcaoType.equalsIgnoreCase("sp3") || lcaoType.indexOf("d") >= 0 ? x4
							: lcaoType.indexOf("c") >= 0 ? x3 : lcaoType.indexOf("b") >= 0 ? x2 : x);
					z.scale(-1);
					x.set(y1);
				}
				else { // needs testing here
					x.cross(z, x);
				}
				break;
			}
			hybridization = "sp2";
			if (lcaoType.indexOf("sp") == 0) { // align z as sp2 orbital
				z.set(lcaoType.equalsIgnoreCase("sp3") || lcaoType.indexOf("d") >= 0 ? x4
						: lcaoType.indexOf("c") >= 0 ? x3 : lcaoType.indexOf("b") >= 0 ? x2 : x);
				z.scale(-1);
				x.set(y1);
				break;
			}
			// align z as p orbital
			z.set(y1);
			if (z.z < 0) {
				z.set(-z.x, -z.y, -z.z);
				x.set(-x.x, -x.y, -x.z);
			}
		}

		x.normalize();
		z.normalize();

		Logger.debug(atom.getIdentity() + " nBonds=" + nBonds + " " + hybridization);
		if (hybridizationCompatible) {
			if (hybridization == "")
				return false;
			if (lcaoType.indexOf("p") == 0) {
				if (hybridization == "sp3")
					return false;
			}
			else {
				if (lcaoType.indexOf(hybridization) < 0)
					return false;
			}
		}
		return true;
	}