コード例 #1
0
        public void TestZoom1_XOnly_XDirection()
        {
            double aspectRatio            = 1.0;
            double cameraDistanceOriginal = 1000;
            double zNear              = 100;
            double zFar               = 10000;
            double widthByZNear       = 0.5;
            double distanceFactor     = 0.75;
            var    targetPosition     = new PointD3D(0, 0, 0);
            var    targetToEye        = new VectorD3D(cameraDistanceOriginal, 0, 0);
            var    cameraUpVector     = new VectorD3D(0, 0, 1);
            var    targetToWorldPoint = new VectorD3D(0, 200, 0);

            PointD3D cameraPosition = targetPosition + targetToEye;
            PointD3D worldPoint     = targetPosition + targetToWorldPoint;

            Assert.AreEqual(0, VectorD3D.DotProduct(targetToEye, targetToWorldPoint), "The test must be set up in a way that targetToEye and targetToWorldPoint are perpendicular to each other");

            var cameraO = new PerspectiveCamera(cameraUpVector, cameraPosition, targetPosition, zNear, zFar, widthByZNear * zNear);

            var screenO = cameraO.GetViewProjectionMatrix(aspectRatio).Transform(worldPoint);

            Assert.AreEqual(0.0, screenO.Y, "Test must be set up so that screen.Y is always zero");

            var cameraN = cameraO.ZoomByGettingCloserToTarget(distanceFactor, screenO.X, screenO.Y, aspectRatio);

            var screenN = cameraN.GetViewProjectionMatrix(aspectRatio).Transform(worldPoint);

            Assert.AreEqual(screenO.X, screenN.X, 1E-3);
            Assert.AreEqual(screenO.Y, screenN.Y, 1E-3);
        }
コード例 #2
0
ファイル: MouseStateHandler.cs プロジェクト: olesar/Altaxo
        /// <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));
        }