/// <summary> /// Creates a transformation matrix that can be used to transform the user-specific /// to device units. /// </summary> /// <param name="deviceWidth">The device width, in device units.</param> /// <param name="deviceHeight">The device height, in device units.</param> /// <param name="userWidth">The device width, in user-specific units.</param> /// <param name="userHeight">The device heigh, in user-specific units.</param> /// <param name="stretchMode"> /// A value indicating how to stretch user-specific units to fit the device units. /// </param> /// <returns>The created transformation matrix.</returns> private Matrix CreateUserToDeviceTransformationMatrix(int deviceWidth, int deviceHeight, double userWidth, double userHeight, UserToDeviceStretchMode stretchMode) { var extents = _currentScopeGraphicsRangeExtents; var deviceCenter = new PointD(deviceWidth / 2 + extents.MinX, deviceHeight / 2 + extents.MinY); var aspectRatioCalculator = new AspectRatioCalculator(deviceWidth, deviceHeight, userWidth, userHeight); var aspectRatioFactor = aspectRatioCalculator.UserToDeviceAspectRatioFactor; switch (stretchMode) { case UserToDeviceStretchMode.UniformToAny: stretchMode = aspectRatioFactor > 1 ? UserToDeviceStretchMode.UniformToHeight : UserToDeviceStretchMode.UniformToWidth; break; case UserToDeviceStretchMode.UniformToFill: stretchMode = aspectRatioFactor < 1 ? UserToDeviceStretchMode.UniformToHeight : UserToDeviceStretchMode.UniformToWidth; break; } switch (stretchMode) { case UserToDeviceStretchMode.UniformToHeight: userWidth = userHeight; deviceWidth = (int)(deviceWidth / aspectRatioCalculator.DeviceAspectRatio); break; case UserToDeviceStretchMode.UniformToWidth: userHeight = userWidth; deviceHeight = (int)(deviceHeight * aspectRatioCalculator.DeviceAspectRatio); break; } return(new Matrix(deviceWidth / userWidth, 0, 0, -deviceHeight / userHeight, deviceCenter.X, deviceCenter.Y)); }
/// <summary> /// Creates a rectangle range the scope contents are rendered to, according to the specified values. /// </summary> /// <returns>The user range.</returns> /// <param name="extents">The extents of the device area to render to.</param> /// <param name="xUserMinSpan">The minimum horizontal (X) span requeste, in user-specific units.</param> /// <param name="yUserMinSpan">The minimum vertical (Y) span requeste, in user-specific units.</param> /// <param name="originOffset">The offset of the origin to the range center, in user-specific units.</param> /// <returns>The created rectangle range or <c>null</c> if no range could be created.</returns> private RectangleRange CreateScopeGraphicsRange(DeviceAreaExtents extents, double xUserMinSpan, double yUserMinSpan, Distance userOriginOffset) { var rangeWidth = extents.Width; var rangeHeight = extents.Height; // As this could result in division by zero or infinite values, // we don't create a range in this case. if (rangeWidth <= 0 || rangeHeight <= 0) { return(null); } double aspectRatioFactor; UserToDeviceStretchMode userToDeviceStretchMode; if (_stretchMode == ScopeStretchMode.Expand) { aspectRatioFactor = new AspectRatioCalculator(rangeWidth, rangeHeight, xUserMinSpan, yUserMinSpan) .UserToDeviceAspectRatioFactor; userToDeviceStretchMode = UserToDeviceStretchMode.UniformToAny; } else { aspectRatioFactor = 1; userToDeviceStretchMode = UserToDeviceStretchMode.Fill; } // Expand the width or height range to utilize any extra space available. var xUserSpan = xUserMinSpan; var yUserSpan = yUserMinSpan; if (aspectRatioFactor > 1) { xUserSpan *= aspectRatioFactor; } else { yUserSpan /= aspectRatioFactor; } var userToDeviceMatrix = CreateUserToDeviceTransformationMatrix(rangeWidth, rangeHeight, xUserSpan, yUserSpan, userToDeviceStretchMode); // Note: "if (matrix != null)" fails. Bug in the equality operator of Matrix? // Consider the origin offset (in user-specific units). userToDeviceMatrix.Translate(+userOriginOffset.Dx, +userOriginOffset.Dy); return(new RectangleRange(rangeWidth, rangeHeight, xUserSpan, yUserSpan, userOriginOffset, userToDeviceMatrix)); }