Rect

From Director Online Wiki
Jump to: navigation, search

Definition

A rect is a list-like object with four numerical parameters, used to define a 2D rect.

Theory

A rectangle is defined by the coordinates of its left, top, right and bottom sides, in that order. Vertical co-ordinates increase from top to bottom. (In 3D co-ordinates, the y value increases from bottom to top). The values are expected to be integers:

rect(left, top, right, bottom)
rect(point(left, top), point(right, bottom))

Practice

It is possible to create a rect which does not adhere to this strict definition. Director will accept these unorthodox rects, in other cases it will produce unexpected results.

  • Floating point values
vRect1 = rect(0.5, 0.5, 10.5, 10.5)
put vRect1
-- rect(0.5000, 0.5000, 10.5000, 10.5000)
put vRect1.width
-- 10
put rect(10, 20, 40, 80) / 3.0
-- rect(3.3333, 6.6667, 13.3333, 26.6667)
  • Reversed top/bottom or left/right
vRect2 = rect(point(10, 10), point(0, 0))
put vRect2
-- rect(10, 10, 0, 0)
put vRect2.width
-- -10

Properties

rects have the following properties:

  • left
  • top
  • right
  • bottom
  • width
  • height

The fastest method for testing whether a rect is equal to rect(0, 0, 0, 0) is to test its width and height:

vRect1     = rect(10, 20, 30, 40)
vRect2     = rect(0, 0, 10, 10)
vIntersect = vRect1.intersect(vRect2)
if vIntersect.width and vIntersect.height then
  -- The two rects intersect
else
  -- There is no intersection
end if

Methods

You can use the following methods with rects. values are reversed: They will all round floating point values to the nearest integer. Those marked with an asterisk may all produce unexpected output values if the top and bottom or left and right are reversed.

Because it rounds to integers, the map() method is not accurate. Inversing the operation may not return the starting rect. See the entry for map() for a more accurate method.

You can also use certain list operations on rects:

vRect = rect(-10, 10, 20 , 40)
put vRect.getAt(2)
-- 10
put vRect.getLast()
-- 40
put vRect.min()
-- -10

Additional Methods

The following method scales one rect so that it fits inside another. This can be useful for displaying images of various dimensions inside a fixed-size area, at the optimum size.

on FitToRect(aSourceRect, aTargetRect) -------------------------------
  -- INPUT: <aSourceRect> and <aTargetRect> should both be rects
  -- OUTPUT: Returns the largest rect with the same proportions as
  --         aSourceRect which fits inside aTargetRect.  The output
  --         rect will be centered with respect to aTargetRect.
  -- NOTE:   The elements of the output rect may be floating point
  --         numbers.  Subsequent rect operations such as inflate()
  --         offset() or map() will round these elements to integers.
  --------------------------------------------------------------------
 
  vLeft   = aTargetRect.left
  vTop    = aTargetRect.top
  vRight  = aTargetRect.right
  vBottom = aTargetRect.bottom
  vWidth  = vRight - vLeft
  vHeight = vBottom - vTop
 
  vTargetRatio  = vWidth / float(vHeight)
  vSourceRatio  = aSourceRect.width / float(aSourceRect.height)
 
  if vTargetRatio > vSourceRatio then
    vAdjust = (vWidth - vHeight * vSourceRatio) / 2
    vLeft   = vLeft + vAdjust
    vRight  = vRight - vAdjust
   
  else
    vAdjust = (vHeight - vWidth / vSourceRatio) / 2
    vTop    = vTop + vAdjust
    vBottom = vBottom - vTop
  end if
 
  vRect = rect(vLeft, vTop, vRight, vBottom)
 
  return vRect
end FitToRect

The following methods align a rect with another rect or with a point.

on RectAlign( aRect, aBaseRect, aSymMode ) ---------------------------
  -- INPUT: <aRect> and <aBaseRect> must be rect objects
  --        <aSymMode> may be an optional mode symbol:
  --         #centerH | #centerV | #leftEdge | #topEdge |
  --         #rightEdge | #bottomEdge
  --         If none of these symbols is given #center is assumed.
  -- OUTPUT: Returns a rect with the same dimensions as aRect,
  --         aligned to <aBaseRect> in <aSymMode>.  Rect values are
  --         rounded to the nearest integer.
  --------------------------------------------------------------------
 
  case aSymMode of
    #leftEdge:
      vOffset = aBaseRect.left - aRect.left
      vOutput = aRect.offset(vOffset, 0)
     
    #topEdge:
      vOffset = aBaseRect.top - aRect.top
      vOutput = aRect.offset(0, vOffset)
     
    #rightEdge:
      vOffset = aBaseRect.right - aRect.right
      vOutput = aRect.offset(vOffset, 0)
     
    #bottomEdge:
      vOffset = aBaseRect.bottom - aRect.bottom
      vOutput = aRect.offset(0, vOffset)
     
    #centerH:
      vCenterH = (aBaseRect.left + aBaseRect.right) / 2
      vCenterV = (aRect.top + aRect.bottom) / 2
      vCenter  = point(vCenterH, vCenterV)
      vOutput  = RectAroundCenter(aRect, vCenter)
     
    #centerV:
      vCenterH = (aRect.left + aRect.right) / 2
      vCenterV = (aBaseRect.top + aBaseRect.bottom) / 2
      vCenter  = point(vCenterH, vCenterV)
      vOutput  = RectAroundCenter(aRect, vCenter)
     
    otherwise: -- center
      vCenter = RectCenter(aBaseRect)
      vOutput = RectAroundCenter(aRect, vCenter)
  end case
 
  return vOutput
end RectAlign
on RectAroundCenter(aRect, aPoint) -----------------------------------
  -- INPUT: <aRect> must be a rect object
  --        <aPoint> must be a point object
  -- OUTPUT: Returns a rect with the same dimensions as aRect,
  --         centered on aPoint.  The rect will extend one pixel more
  --         to the right or bottom than to the left and top if its
  --         width or height is an odd number of pixels.
  --------------------------------------------------------------------
 
  vWidth  = aRect.width
  vHeight = aRect.height
  vLeft   = aPoint.locH - vWidth / 2
  vTop    = aPoint.locV - vHeight / 2
  vRight  = vLeft + vWidth
  vBottom = vTop + vHeight
 
  vOutput = rect(vLeft, vTop, vRight, vBottom)
 
  return vOutput
end RectAroundCenter

The following method returns the center of a rect using the nearest integer values.

on RectCenter(aRect) -------------------------------------------------
  -- INPUT: <aRect> must be a rect object
  -- OUTPUT: Returns the center point of a rect, rounded to the
  --         nearest integer
  --------------------------------------------------------------------
 
  vCenterH = (aRect.left + aRect.right) / 2
  vCenterV = (aRect.top + aRect.bottom) / 2
  vCenter  = point(vCenterH, vCenterV)
 
  return vCenter
end RectCenter

See also