'From Cuis 2.6 of 10 August 2010 [latest update: #540] on 28 August 2010 at 9:56:32 pm'!

!Rectangle commentStamp: 'nice 7/25/2010 14:56' prior: 0!
I represent a rectangular area of the screen. Arithmetic functions take points as arguments and carry out scaling and translating operations to create new instances of me. Rectangle functions create new instances by determining intersections of rectangles with rectangles.

Note 1: only rectangles parallel to reference frame (Screen) can be represented by this class.

Note 2: the Rectangle is represented by two extremities of one diagonal. By convention, it must be the diagonal:
	from rectangle origin (the point having smallest coordinates in reference frame),
	to rectangle corner (the point having largest coordinates in reference frame).

Note 3: Screen coordinates conventions are:
	x is horizontal axis, zero at left border, oriented toward right;
	y is vertical axis, zero at top border, oriented toward bottom.
This corresponds to the latin convention for writing text from left to right and top to bottom.

Note 4: the Rectangle extent is obtained by subtracting rectangle origin to rectangle corner coordinates.
If this leads to a negative width (extent x coordinate) and/or a negative height (extent y coordinate), then the Rectangle is degenerated and considered empty.

Instance variables:
	origin	<Point> the coordinates of corner having smallest coordinates (top left in Screen coordinates)
	corner	<Point> the coordinates of corner having largest coordinates (bottom right in Screen coordinates)
!


!Rectangle methodsFor: 'rectangle functions' stamp: 'ar 10/25/2005 17:22'!
areasOutside: aRectangle
	"Answer an Array of Rectangles comprising the parts of the receiver not 
	intersecting aRectangle."

	| areas yOrigin yCorner |
	"Make sure the intersection is non-empty"
     (self intersects: aRectangle)
		ifFalse: [^Array with: self].
	areas := OrderedCollection new.
	aRectangle origin y > origin y
		ifTrue: [areas addLast: (origin corner: corner x @ (yOrigin := aRectangle origin y))]
		ifFalse: [yOrigin := origin y].
	aRectangle corner y < corner y
		ifTrue: [areas addLast: (origin x @ (yCorner := aRectangle corner y) corner: corner)]
		ifFalse: [yCorner := corner y].
	aRectangle origin x > origin x 
		ifTrue: [areas addLast: (origin x @ yOrigin corner: aRectangle origin x @ yCorner)].
	aRectangle corner x < corner x 
		ifTrue: [areas addLast: (aRectangle corner x @ yOrigin corner: corner x @ yCorner)].
	^areas! !

!Rectangle methodsFor: 'testing' stamp: 'nice 6/20/2010 21:32'!
intersects: aRectangle 
	"Answer whether aRectangle intersects the receiver anywhere."
	"Optimized; old code answered:
		(origin max: aRectangle origin) < (corner min: aRectangle corner)"

	| rOrigin rCorner |
	rOrigin := aRectangle origin.
	rCorner := aRectangle corner.
	rCorner x <= origin x	ifTrue: [^ false].
	rCorner y <= origin y	ifTrue: [^ false].
	rOrigin x >= corner x	ifTrue: [^ false].
	rOrigin y >= corner y	ifTrue: [^ false].
"None of the two rectangle shall be empty"
	corner x <= origin x	ifTrue: [^ false].
	corner y <= origin y	ifTrue: [^ false].
	rCorner x <= rOrigin x	ifTrue: [^ false].
	rCorner y <= rOrigin y	ifTrue: [^ false].
	^ true
! !

!Rectangle methodsFor: 'transforming' stamp: 'nice 6/20/2010 21:27'!
flipBy: direction centerAt: aPoint 
	"Return a copy flipped #vertical or #horizontal, about aPoint."
	| futureOrigin futureCorner |
	direction == #horizontal
		ifTrue:
			[futureOrigin := self topRight.
			futureCorner := self bottomLeft]
		ifFalse: [direction == #vertical
			ifTrue:
				[futureOrigin := self bottomLeft.
				futureCorner := self topRight]
			ifFalse: [self error: 'unrecognizable direction']].
	^ (futureOrigin flipBy: direction centerAt: aPoint)
		corner: (futureCorner flipBy: direction centerAt: aPoint)! !

!Rectangle methodsFor: 'transforming' stamp: 'nice 6/20/2010 22:01'!
rotateBy: direction centerAt: aPoint
	"Return a copy rotated #right, #left, or #pi about aPoint"
	| futureOrigin futureCorner |
	direction == #pi
		ifTrue:
			[futureOrigin := self corner.
			futureCorner := self origin]
		ifFalse: [direction == #left
			ifTrue:
				[futureOrigin := self topRight.
				futureCorner := self bottomLeft]
			ifFalse: [direction == #right
				ifTrue:
					[futureOrigin := self bottomLeft.
					futureCorner := self topRight]
				ifFalse: [self error: 'unrecognizable direction']]].
	^ (futureOrigin rotateBy: direction centerAt: aPoint)
		corner: (futureCorner rotateBy: direction centerAt: aPoint)! !

!Rectangle methodsFor: 'printing' stamp: 'nice 11/1/2009 20:27'!
storeOn: aStream 
	"printed form is good for storing too"
	
	aStream nextPut: $(.
	self printOn: aStream.
	aStream nextPut: $).! !


!Rectangle class methodsFor: 'instance creation' stamp: 'md 12/3/2004 00:02'!
left: leftNumber right: rightNumber top: topNumber bottom: bottomNumber 
	"Answer an instance of me whose left, right, top, and bottom coordinates 
	are determined by the arguments."

	^ self basicNew setOrigin: leftNumber @ topNumber corner: rightNumber @ bottomNumber! !

!Rectangle class methodsFor: 'instance creation' stamp: 'md 12/3/2004 00:04'!
origin: originPoint corner: cornerPoint 
	"Answer an instance of me whose corners (top left and bottom right) are 
	determined by the arguments."

	^self basicNew setOrigin: originPoint corner: cornerPoint! !

!Rectangle class methodsFor: 'instance creation' stamp: 'md 12/3/2004 00:03'!
origin: originPoint extent: extentPoint 
	"Answer an instance of me whose top left corner is originPoint and width 
	by height is extentPoint."

	^self basicNew setOrigin: originPoint corner: originPoint + extentPoint! !

