public void ComputeCoordinatesSubtree(Matrix4d parentTransform, Node parentNode) { if (parentNode.nodeNumDecendents == 0) { return; } float parentRadiusE = HyperbolicMath.euclideanDistance(parentNode.nodeHemsphereRadius); float lastPhi = 0.0f; Matrix4d rotPhi = HyperbolicTransformation.I4; Point4d childCenterAbsolute = new Point4d(); Point4d childPoleAbsolute = new Point4d(); foreach (Node child in parentNode.nodeChildren) { float childRadiusE = HyperbolicMath.euclideanDistance(child.nodeHemsphereRadius); float childPhi = child.nodeHemspherePhi; if (!(Mathf.Abs(childPhi - lastPhi) < EPSILON)) { lastPhi = childPhi; rotPhi = HyperbolicTransformation.buildZRotation(childPhi); } Matrix4d rot = HyperbolicTransformation.buildXRotation(child.nodeHemsphereTheta); rot = rot * rotPhi; childCenterAbsolute.set(parentRadiusE, 0.0f, 0.0f, 1.0f); rot.transform(childCenterAbsolute); float childPoleE = HyperbolicMath.euclideanDistance(parentNode.nodeHemsphereRadius + child.nodeHemsphereRadius); childPoleAbsolute.set(childPoleE, 0.0f, 0.0f, 1.0f); rot.transform(childPoleAbsolute); parentTransform.transform(childCenterAbsolute); parentTransform.transform(childPoleAbsolute); child.nodeEuclideanPosition = childCenterAbsolute; //graph.setNodeLayoutCoordinates(child, childCenterAbsolute); Matrix4d childTransform = HyperbolicTransformation.buildCanonicalOrientation(childCenterAbsolute, childPoleAbsolute); ComputeCoordinatesSubtree(childTransform, child); } }