Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1529

[vb6] Scale + Rotation Routine for Sizing Objects

$
0
0
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
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

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.
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

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
Attached Images
  

Viewing all articles
Browse latest Browse all 1529

Trending Articles