--- a/Rectangle.st Fri Jan 20 20:00:45 2017 +0100
+++ b/Rectangle.st Fri Jan 20 22:58:32 2017 +0100
@@ -1518,31 +1518,128 @@
"Created: 25.1.1997 / 17:30:21 / cg"
!
-areasOutside: aRectangle
- "Answer an Array of Rectangles comprising the parts of the receiver not
- intersecting aRectangle."
+areasOutside:aRectangle
+ "Answer an Array of Rectangles comprising the parts of the receiver
+ not intersecting aRectangle.
+ That is all areas with no common pixels."
+
+ |areas|
+
+ "Make sure the intersection is non-empty"
+ (self origin <= aRectangle corner and: [aRectangle origin <= self corner]) ifFalse: [
+ ^ Array with: self
+ ].
+ areas := OrderedCollection new.
+ self areasOutside:aRectangle do:[:r | areas add:r].
+ ^ areas asArray
+
+ "/ cg: the old code below was wrong ...
- | areas yOrigin yCorner origin corner|
+"/ "----------------------------------------------------------------
+"/ | added for GNU-ST compatibility
+"/ |
+"/ | author: Doug McCallum <uunet!!ico.isc.com!!dougm>
+"/ |
+"/ |areasOutside: aRectangle
+"/ | most complicated of the Rectangle primitives
+"/ | The basic methodology is to first determine that there is an
+"/ | intersection by finding the overlapping rectangle. From the
+"/ | overlapping rectangle, first determine if it runs along an edge.
+"/ | If it doesn't, extend the rectangle up to the top edge and add
+"/ | the new rectangle to the collection and start the rest of the
+"/ | process. If the left edge does not touch the left edge of self,
+"/ | extend it to the edge saving the new rectangle. Then do the
+"/ | same to the right edge. Then check top and bottom edges. Most
+"/ | of the time only 2 or 3 rectangles get formed, occasionally 4.
+"/ | It should be possible to never get more than 3 but requires more
+"/ | work.
+"/ ----------------------------------------------------------------"
+"/
+"/ | collect iRect tmp |
+"/
+"/ iRect := self intersect: aRectangle.
+"/ iRect isNil ifTrue: [^nil]. "case of no intersection"
+"/ "the collect collection gathers Rectangles"
+"/ collect := OrderedCollection new: 4.
+"/ "is it floating or on the edge?"
+"/ (((((iRect top) ~= self top)
+"/ and: [ (iRect bottom) ~= self bottom ])
+"/ and: [ (iRect left) ~= self left ])
+"/ and: [ (iRect right) ~= self right ] )
+"/ ifTrue: "entirely in the center."
+"/ [tmp := Rectangle origin: (Point x: iRect left y: self top)
+"/ corner: iRect bottomRight.
+"/ collect add: tmp.
+"/ iRect := iRect merge: tmp].
+"/ ((iRect left) ~= self left)
+"/ ifTrue: "doesn't touch left edge so make it touch"
+"/ [tmp := Rectangle origin: (Point x: self left y: iRect top)
+"/ corner: iRect bottomLeft.
+"/ collect add: tmp.
+"/ "merge new (tmp) with overlap to keep track"
+"/ iRect := iRect merge: tmp].
+"/ ((iRect right) ~= self right)
+"/ ifTrue: "doesn't touch right edge so extend it"
+"/ [tmp := Rectangle origin: iRect topRight
+"/ corner: (Point x: self right y: iRect bottom).
+"/ collect add: tmp.
+"/ iRect := iRect merge: tmp].
+"/ (((iRect left) ~= self left) or: [(iRect top) ~= self top])
+"/ ifTrue: "whole top part can be taken now"
+"/ [tmp := Rectangle origin: self origin corner: iRect topRight.
+"/ collect add: tmp].
+"/ (((iRect right) ~= self right) or: [(iRect bottom) ~= self bottom])
+"/ ifTrue: "whole bottom open and can be taken"
+"/ [tmp := Rectangle origin: iRect bottomLeft corner: self corner.
+"/ collect add: tmp].
+"/ ^collect
+!
+
+areasOutside:aRectangle do:aBlock
+ "evaluate aBlock for Rectangles comprising the parts of the receiver
+ not intersecting aRectangle.
+ That is all areas with no common pixels."
+
+ |yOrigin yCorner origin corner|
origin := self origin.
corner := self corner.
"Make sure the intersection is non-empty"
(origin <= aRectangle corner and: [aRectangle origin <= corner])
- 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
+ ifFalse: [ aBlock value:self. ^ self].
+ aRectangle origin y > origin y ifTrue: [
+ aBlock value: (origin corner: corner x @ (yOrigin := aRectangle origin y))
+ ] ifFalse: [
+ yOrigin := origin y
+ ].
+ aRectangle corner y < corner y ifTrue: [
+ aBlock value: (origin x @ (yCorner := aRectangle corner y) corner: corner)
+ ] ifFalse: [
+ yCorner := corner y
+ ].
+ aRectangle origin x > origin x ifTrue: [
+ aBlock value: (origin x @ yOrigin corner: aRectangle origin x @ yCorner)
+ ].
+ aRectangle corner x < corner x ifTrue: [
+ aBlock value: (aRectangle corner x @ yOrigin corner: corner x @ yCorner)
+ ].
+
+ "
+ self assert:
+ ((0@0 corner:100@100) areasOutside:(0@0 corner:50@50)) asArray
+ = { (Rectangle origin:0@50 extent:100@50) . (Rectangle origin:50@0 extent:50@50) }
+
+ self assert:
+ ((0@0 corner:150@100) areasOutside:(0@0 corner:100@100)) asArray
+ = { (Rectangle origin:100@0 extent:50@100) }
+
+ self assert:
+ ((0@0 corner:100@150) areasOutside:(0@0 corner:100@100)) asArray
+ = { (Rectangle origin:0@100 extent:100@50) }
+ "
+
"/ cg: the old code below was wrong ...
"/ "----------------------------------------------------------------