diff -r a7000a97f464 -r a12e4696432c Rectangle.st --- 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 +"/ | +"/ |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 ... "/ "----------------------------------------------------------------