The two routines shown below can be used by anyone that needs one of the following results:
1. Scale an object to a destination object to include rotation & proportional scaling. Fit rotated bounds to container
2. Scale a destination object based on another object that is rotated. Fit container to rotated bounds
The routines are designed to include rotation in the calculations; though an angle of zero degrees can be passed. The word 'container' can be a bitmap, picturebox, your custom usercontrol, or anything that has dimensions. The word 'bounds' is simply a rectangle associated with some object: image, font, etc.
1. This function will take some unrotated, unscaled bounds and scale them to a target container. Rotation of the bounds is an option along with a few other options. The returned scale would be applied to the passed bounds
Samples: The container is shown as a black rectangle
The 1st row of images passes the ScaleForAllAngles parameter as false. You will see that the image size can change dependent on the angle or rotation. Returned scale is variable
The 2nd row of images passes the ScaleForAllAngles parameter as true. You will see that the image maintains the same size at each angle of rotation. Returned scale is constant
![Name: autofit.jpg
Views: 29
Size: 31.9 KB]()
2. This function will take some unrotated, scaled bounds and return the dimensions that a container would need to be in order to display the bounds after rotation.
Samples: The container is shown as a black rectangle
The 1st row of images passes the ScaleForAllAngles parameter as false. You will see that the container size can change dependent on the angle or rotation. The container is fitted to the bounds, after rotation. Returned dimensions are variable
The 2nd row of images passes the ScaleForAllAngles parameter as true. You will see that the container size is constant at each angle of rotation. Returned dimensions are constant.
![Name: autosize.jpg
Views: 26
Size: 29.9 KB]()
1. Scale an object to a destination object to include rotation & proportional scaling. Fit rotated bounds to container
2. Scale a destination object based on another object that is rotated. Fit container to rotated bounds
The routines are designed to include rotation in the calculations; though an angle of zero degrees can be passed. The word 'container' can be a bitmap, picturebox, your custom usercontrol, or anything that has dimensions. The word 'bounds' is simply a rectangle associated with some object: image, font, etc.
1. This function will take some unrotated, unscaled bounds and scale them to a target container. Rotation of the bounds is an option along with a few other options. The returned scale would be applied to the passed bounds
Code:
Function ScaleBoundsToContainer(ByVal BoundsWidth As Long, ByVal BoundsHeight As Long, _
ByVal ContainerWidth As Long, ByVal ContainerHeight As Long, _
Optional ByVal Angle As Single = 0!, _
Optional ByVal ScaleForAllAngles As Boolean = False, _
Optional ByVal MaxRatioIsActualSize As Boolean = False, _
Optional ByVal LimitBoundsToContainer As Boolean = True) As Single
' Function returns a proportional scale ratio, relative to the passed bounds and
' container dimensions at a single angle or all angles
' If function returns zero, an error occurred or invalid parameters passed
' Parameters:
' BoundsWidth,BoundsHeight are the unrotated, base dimensions to be scaled
' ContainerWidth,ContainerHeight are the dimensions to restrict scaling
' Angle can be any value, including negative and beyond 360 degrees
' ScaleForAllAngles if true will return a scale that allows bounds to be rotated across all 360
' degree angles within the container and without the bounds changing size per degree of rotation
' If false, the scale returned is for the Angle passed & can change from angle to angle
' MaxRatioIsActualSize if true will never allow function to return a scale > 1.0
' LimitBoundsToContainer if false will always return a scale of 1.0
Dim xRatio As Double, yRatio As Double
Dim sinT As Double, cosT As Double
Dim cx As Double, cy As Double
If LimitBoundsToContainer = False Then
xRatio = 1#
ElseIf (BoundsWidth > 0& And BoundsHeight > 0&) Then ' sanity checks
If (ContainerWidth > 0& And ContainerHeight > 0&) Then
On Error GoTo ExitRoutine
If ScaleForAllAngles Then
xRatio = Sqr(BoundsWidth * BoundsWidth + BoundsHeight * BoundsHeight)
yRatio = ContainerHeight / xRatio
xRatio = ContainerWidth / xRatio
Else
xRatio = ContainerWidth / BoundsWidth
yRatio = ContainerHeight / BoundsHeight
Angle = Abs((Fix(Angle) Mod 180) + (Angle - Fix(Angle)))
If Angle > 90! Then Angle = 180! - Angle
' note: actual angle is not needed for this function. Threshold angles to 0-90
' i.e., 45,135,225,315,-45 (multiples of 45) are not same angles, however
' their 'shape' is the the same. The shape is what is used for the scaling
If Angle > 0! Then
cx = (4# * Atn(1)) / 180# ' conversion factor for degree>radian
sinT = Sin(Angle * cx): cosT = Cos(Angle * cx)
If xRatio > yRatio Then xRatio = yRatio
cx = BoundsWidth * xRatio ' scale bounds to container
cy = BoundsHeight * xRatio
' get relative scale of container after rotation
xRatio = ContainerHeight * ContainerHeight / (cx * sinT + cy * cosT)
yRatio = ContainerWidth * ContainerHeight / (cx * cosT + cy * sinT)
If xRatio < yRatio Then yRatio = xRatio
xRatio = yRatio * ContainerWidth / ContainerHeight
xRatio = xRatio / BoundsWidth ' recalculate scale of bounds to container
yRatio = yRatio / BoundsHeight
End If
End If
If xRatio > yRatio Then xRatio = yRatio ' use lower of two ratios
End If
End If
If MaxRatioIsActualSize = True Then ' limit/restrict scale to 1:1 ?
If xRatio > 1# Then xRatio = 1#
End If
ScaleBoundsToContainer = xRatio
ExitRoutine:
End Function
The 1st row of images passes the ScaleForAllAngles parameter as false. You will see that the image size can change dependent on the angle or rotation. Returned scale is variable
The 2nd row of images passes the ScaleForAllAngles parameter as true. You will see that the image maintains the same size at each angle of rotation. Returned scale is constant
2. This function will take some unrotated, scaled bounds and return the dimensions that a container would need to be in order to display the bounds after rotation.
Code:
Function ScaleContainerToBounds(ByVal BoundsWidth As Long, ByVal BoundsHeight As Long, _
ByRef ContainerWidth As Long, ByRef ContainerHeight As Long, _
Optional ByVal Angle As Single = 0!, _
Optional ByVal ScaleForAllAngles As Boolean = False) As Boolean
' Function returns minimum size of a container to view unclipped bounds at passed rotation
' If function returns False, an error occurred or invalid parameters passed
' Parameters:
' BoundsWidth,BoundsHeight are the unrotated, source dimensions
' ContainerWidth,ContainerHeight are the returned dimensions calculated from passed bounds and angle
' if function returns False, these parameters when returned are undefined and should be ignored
' Angle can be any value, including negative and beyond 360 degrees
' ScaleForAllAngles if true will return dimensions that allows bounds to be rotated across all 360
' degree angles within the container without clipping
' If false, the dimensions returned is for the Angle passed & can change from angle to angle
If (BoundsWidth < 1& Or BoundsHeight < 1&) Then Exit Function
Dim sinT As Double, cosT As Double
Dim ctrX As Double, ctrY As Double
Dim dScaler As Double
On Error GoTo ExitRoutine
If ScaleForAllAngles Then
dScaler = Sqr(BoundsWidth * BoundsWidth + BoundsHeight * BoundsHeight)
If dScaler - Int(dScaler) > 0.00001 Then dScaler = dScaler + 1#
ContainerWidth = Int(dScaler)
ContainerHeight = ContainerWidth
Else
Angle = Abs((Fix(Angle) Mod 180) + (Angle - Fix(Angle)))
If Angle > 90! Then Angle = 180! - Angle
' note: actual angle is not needed for this function. Threshold angles to 0-90
' i.e., 45,135,225,315,-45 (multiples of 45) are not same angles, however
' their 'shape' is the the same. The shape is what is used for the scaling
If Angle = 0! Then
ContainerHeight = BoundsHeight
ContainerWidth = BoundsWidth
Else
dScaler = (4# * Atn(1)) / 180# ' conversion factor for degree>radian
sinT = Sin(Angle * dScaler): cosT = Cos(Angle * dScaler)
ctrX = BoundsWidth / 2#: ctrY = BoundsHeight / 2#
dScaler = (-ctrX * sinT) + (-ctrY * cosT)
dScaler = (BoundsWidth - ctrX) * sinT + (BoundsHeight - ctrY) * cosT - dScaler
If dScaler - Int(dScaler) > 0.00001 Then dScaler = dScaler + 1#
ContainerHeight = Int(dScaler)
dScaler = ((-ctrX * cosT) - (BoundsHeight - ctrY) * sinT)
dScaler = (BoundsWidth - ctrX) * cosT - (-ctrY * sinT) - dScaler
If dScaler - Int(dScaler) > 0.00001 Then dScaler = dScaler + 1#
ContainerWidth = Int(dScaler)
End If
End If
ScaleContainerToBounds = True
ExitRoutine:
End Function
The 1st row of images passes the ScaleForAllAngles parameter as false. You will see that the container size can change dependent on the angle or rotation. The container is fitted to the bounds, after rotation. Returned dimensions are variable
The 2nd row of images passes the ScaleForAllAngles parameter as true. You will see that the container size is constant at each angle of rotation. Returned dimensions are constant.