/// <summary> /// Gets the hit point on that plane of the active layer rectangle, that is facing the camera. /// </summary> /// <param name="doc">The graph document containing the active layer.</param> /// <param name="activeLayer">The active layer of the graph document.</param> /// <param name="hitposition">Hit point in relative screen coordinates. The z-component is the aspect ratio of the screen (y/x).</param> /// <param name="hitPointOnPlaneInActiveLayerCoordinates">Output: The hit point on the plane of the active layer that faces the camera. The hit point is returned in active layer coordinates.</param> /// <param name="rotationsRadian">The rotation angles that can be used e.g. to orient text so that the text is most readable from the current camera setting. Rotation angle around x is the x-component of the returned vector, and so on.</param> /// <exception cref="InvalidProgramException">There should always be a plane of a rectangle that can be hit!</exception> public static void GetHitPointOnActiveLayerPlaneFacingTheCamera(GraphDocument doc, HostLayer activeLayer, PointD3D hitposition, out PointD3D hitPointOnPlaneInActiveLayerCoordinates, out VectorD3D rotationsRadian) { var activeLayerTransformation = activeLayer.TransformationFromRootToHere(); var camera = doc.Camera; var hitData = new HitTestPointData(camera.GetHitRayMatrix(hitposition)); hitData = hitData.NewFromAdditionalTransformation(activeLayerTransformation); // now hitdata are in layer cos var targetToEye = hitData.WorldTransformation.Transform(camera.TargetToEyeVectorNormalized); // targetToEye in layer coordinates var upEye = hitData.WorldTransformation.Transform(camera.UpVectorPerpendicularToEyeVectorNormalized); // camera up vector in layer coordinates // get the face which has the best dot product between the eye vector of the camera and the plane's normal var layerRect = new RectangleD3D(PointD3D.Empty, activeLayer.Size); double maxval = double.MinValue; PlaneD3D maxPlane = PlaneD3D.Empty; foreach (var plane in layerRect.Planes) { double val = VectorD3D.DotProduct(plane.Normal, targetToEye); if (val > maxval) { maxval = val; maxPlane = plane; } } bool isHit = hitData.IsPlaneHitByRay(maxPlane, out hitPointOnPlaneInActiveLayerCoordinates); // hitPointOnPlane is in layer coordinates too if (!isHit) throw new InvalidProgramException("There should always be a plane of a rectangle that can be hit!"); VectorD3D zaxis = maxPlane.Normal; VectorD3D yaxis = upEye; // Find y axis perpendicular to zaxis maxval = double.MinValue; foreach (var plane in layerRect.Planes) { double val = VectorD3D.DotProduct(plane.Normal, upEye); if (val > maxval && 0 == VectorD3D.DotProduct(plane.Normal, zaxis)) { maxval = val; yaxis = plane.Normal; } } var xaxis = VectorD3D.CrossProduct(yaxis, zaxis); // now we have all information about the spatial position and orientation of the text: // hitPointOnPlane is the position of the text // maxPlane.Normal is the face orientation of the text // maxUpVector is the up orientation of the text double cx, sx, cy, sy, cz, sz; sy = xaxis.Z; if (1 != Math.Abs(sy)) { cy = Math.Sqrt(1 - sy * sy); cz = xaxis.X / cy; sz = xaxis.Y / cy; sx = yaxis.Z / cy; cx = zaxis.Z / cy; } else // sy is +1, thus cy is zero { // we set x-rotation to zero, i.e. cx==1 and sx==0 cy = 0; cx = 1; sx = 0; cz = yaxis.Y; sz = -yaxis.X; } rotationsRadian = new VectorD3D(Math.Atan2(sx, cx), Math.Atan2(sy, cy), Math.Atan2(sz, cz)); }
/// <summary> /// Gets the principal coordinate system that results of the camera facing a layer. The plane of the layer that best faced the camera is used for the calculations. /// The normal of that layer is returned as z-axis, the vector that best matches the up-vector of the camera is becoming the y-axis, /// and the x-axis results from the z-axis and the y-axis. /// </summary> /// <param name="camera">The camera.</param> /// <param name="activeLayer">The active layer of the graph document.</param> /// <param name="transformation">Matrix that contains the principal axes as described above. The axes coordinates are in the coordinates of the layer provided in the argument <paramref name="activeLayer"/>.</param> /// <exception cref="InvalidProgramException">There should always be a plane of a rectangle that can be hit!</exception> public static void GetCoordinateSystemBasedOnLayerPlaneFacingTheCamera(CameraBase camera, HostLayer activeLayer, out Matrix3x3 transformation) { PointD3D hitposition = new PointD3D(0.5, 0.5, 1); // this hit position is arbitrary, every other position should work similarly var activeLayerTransformation = activeLayer.TransformationFromRootToHere(); var hitData = new HitTestPointData(camera.GetHitRayMatrix(hitposition)); hitData = hitData.NewFromAdditionalTransformation(activeLayerTransformation); // now hitdata are in layer cos var targetToEye = hitData.WorldTransformation.Transform(camera.TargetToEyeVectorNormalized); // targetToEye in layer coordinates var upEye = hitData.WorldTransformation.Transform(camera.UpVectorPerpendicularToEyeVectorNormalized); // camera up vector in layer coordinates // get the face which has the best dot product between the eye vector of the camera and the plane's normal var layerRect = new RectangleD3D(PointD3D.Empty, activeLayer.Size); double maxval = double.MinValue; PlaneD3D maxPlane = PlaneD3D.Empty; foreach (var plane in layerRect.Planes) { double val = VectorD3D.DotProduct(plane.Normal, targetToEye); if (val > maxval) { maxval = val; maxPlane = plane; } } // bool isHit = hitData.IsPlaneHitByRay(maxPlane, out hitPointOnPlaneInActiveLayerCoordinates); // hitPointOnPlane is in layer coordinates too // if (!isHit) // throw new InvalidProgramException("There should always be a plane of a rectangle that can be hit!"); VectorD3D zaxis = maxPlane.Normal; VectorD3D yaxis = upEye; // Find y axis perpendicular to zaxis maxval = double.MinValue; foreach (var plane in layerRect.Planes) { double val = VectorD3D.DotProduct(plane.Normal, upEye); if (val > maxval && 0 == VectorD3D.DotProduct(plane.Normal, zaxis)) { maxval = val; yaxis = plane.Normal; } } var xaxis = VectorD3D.CrossProduct(yaxis, zaxis); // now we have all information about the spatial position and orientation of the text: // hitPointOnPlane is the position of the text // maxPlane.Normal is the face orientation of the text // maxUpVector is the up orientation of the text xaxis = xaxis.Normalized; yaxis = yaxis.Normalized; zaxis = zaxis.Normalized; transformation = new Matrix3x3( xaxis.X, yaxis.X, zaxis.X, xaxis.Y, yaxis.Y, zaxis.Y, xaxis.Z, yaxis.Z, zaxis.Z ); }