
Object subclass: #Rectangle
  instanceVariableNames: 
    'origin corner '
  classVariableNames: ''
  poolDictionaries: 
    'CharacterConstants ' !

!Rectangle class methods !

origin: originPoint corner: cornerPoint
        "Answer a Rectangle with origin and corner points
         described by originPoint and cornerPoint."
    ^self new origin: originPoint corner: cornerPoint!

origin: originPoint extent: extentPoint
        "Answer a Rectangle whose origin and
         extent (width and height) are
         described by originPoint and
         extentPoint."
    ^self new origin: originPoint extent: extentPoint! !


!Rectangle methods !

bottom
        "Answer the y-coordinate of
         the bottom of the receiver."
    ^corner y!

center
        "Answer a Point, the
         center of the receiver."
    ^(corner + origin) // 2!

containsPoint: aPoint
        "Answer true if aPoint is contained within
         the receiver, else answer false."
    ^(origin <= aPoint) and: [aPoint < corner]!

corner
        "Answer a Point, the bottom right
         corner of the receiver."
    ^corner!

corner: aPoint
        "Change the receiver so that its bottom
         right corner is aPoint without changing
         its extent."
    self moveBy: aPoint - corner!

expandBy: delta
        "Answer a Rectangle which is the receiver expanded
         by delta, where delta is a Rectangle, a Point or
         a Number."
    delta class == Rectangle
        ifTrue: [
            ^origin - delta origin
                corner: corner + delta corner]
        ifFalse: [
            ^origin - delta
                corner: corner + delta]!

extent
        "Answer a Point representing the
         receiver width and height."
    ^self width @ self height!

extent: aPoint
        "Change the extent of receiver to aPoint."
    self width: aPoint x.
    self height: aPoint y!

height
        "Answer a number representing
         the receiver height."
    ^corner y - origin y!

height: aNumber
        "Change the receiver height to aNumber."
    corner y: origin y + aNumber!

insetBy: delta
        "Answer a Rectangle which is the receiver
         inset by delta, where delta is a Rectangle,
         a Point or a Number."
    delta class == Rectangle
        ifTrue: [
            ^origin + delta origin
                corner: corner - delta corner]
        ifFalse: [
            ^origin + delta
                corner: corner - delta]!

intersect: aRectangle
        "Answer a Rectangle representing the area in
         which the receiver and aRectangle overlap."
    ^(origin max: aRectangle origin)
        corner: (corner min: aRectangle corner)!

intersects: aRectangle
        "Answer true if the receiver and aRectangle have
         any area in common, else answer false."
    ^origin < aRectangle corner
        and: [aRectangle origin < corner]!

left
        "Answer the x-coordinate of the origin."
    ^origin x!

merge: aRectangle
        "Answer the smallest Rectangle which
         contains the receiver and aRectangle."
    ^(origin min: aRectangle origin)
        corner: (corner max: aRectangle corner)!

moveBy: aPoint
        "Increment the receiver origin
         and corner by aPoint."
    origin := origin + aPoint.
    corner := corner + aPoint!

moveTo: aPoint
        "Move the receiver to aPoint."
    self moveBy: aPoint - origin!

nonIntersections: aRectangle
        "Answer an OrderedCollection of
         rectangles describing areas of
         the receiver outside aRectangle."
    | areas |
    (self intersects: aRectangle)
        ifFalse: [^Array with: self].
    ((aRectangle containsPoint: origin)
        and: [aRectangle containsPoint: corner])
            ifTrue: [ ^#() ].
    areas := OrderedCollection new: 4.
    (aRectangle top > self top)
        ifTrue: [ areas add:
            (origin corner: corner x @ aRectangle top)].
    (aRectangle bottom < self bottom)
        ifTrue: [ areas add:
            (origin x @ aRectangle bottom corner: corner)].
    (aRectangle left > self left)
        ifTrue: [ areas add:
            ((origin x @ (origin y max: aRectangle top))
                corner:
                    (aRectangle left
                        @ (corner y min: aRectangle bottom)))].
    (aRectangle right < self right)
        ifTrue: [ areas add:
            ((aRectangle right @ (origin y max: aRectangle top))
                corner:
                    (corner x
                        @ (corner y min: aRectangle bottom)))].
    ^areas!

origin
        "Answer a Point, the top left
         corner of the receiver."
    ^origin!

origin: originPoint corner: cornerPoint
        "Change the receiver's top left corner to
         originPoint and its bottom right corner to
         cornerPoint."
    origin := originPoint.
    corner := cornerPoint!

origin: originPoint extent: extentPoint
        "Change the receiver's top left corner to
         originPoint and its extent to extentPoint."
    self
        origin: originPoint
        corner: originPoint + extentPoint!

printOn: aStream
        "Append the ASCII representation of
         the receiver to aStream."
    origin printOn: aStream.
    aStream nextPutAll: ' corner: '.
    corner printOn: aStream!

right
        "Answer the the x-coordinate of the
         receiver's bottom right corner."
    ^corner x!

rounded
        "Answer the receiver with the coordinates of
         its origin and corner rounded to integers."
    origin := origin rounded.
    corner := corner rounded.
    ^self!

scaleBy: delta
        "Answer a Rectangle with the receiver
         origin and corner multiplied by delta,
         where delta is either a Number or a Point."
    ^origin * delta
        corner: corner * delta!

scaleTo: aRectangle
        "Answer a Rectangle whose size is
         proportional to the receiver with
         ratios specified by aRectangle."
    ^(aRectangle scaleBy: self extent) truncated
        moveBy: origin!

top
        "Answer the y-coordinate of
         the origin of the receiver."
    ^origin y!

translateBy: delta
        "Answer a Rectangle which is the receiver with
         position incremented by delta, where delta is
         either a Number or a Point."
    ^origin + delta
        corner: corner + delta!

truncated
        "Answer the receiver with the coordinates of
         its origin and corner truncated to integers."
    origin := origin truncated.
    corner := corner truncated.
    ^self!

width
        "Answer a number representing the receiver width."
    ^corner x - origin x!

width: anInteger
        "Change the receiver width to anInteger."
    corner x: origin x + anInteger! !
