'From Squeak 1.18 of December 12, 1996 on 15 March 1997 at 11:45:18 pm'! Point subclass: #SmallPoint instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Graphics-Primitives'! !Point methodsFor: 'comparing'! < aPoint "Answer whether the receiver is above and to the left of aPoint." ^self x < aPoint x and: [self y < aPoint y]! <= aPoint "Answer whether the receiver is neither below nor to the right of aPoint." ^self x <= aPoint x and: [self y <= aPoint y]! = aPoint "Refer to the comment in Object|=." ^self species = aPoint species and: [self x = aPoint x and: [self y = aPoint y]]! > aPoint "Answer whether the receiver is below and to the right of aPoint." ^self x > aPoint x and: [self y > aPoint y]! >= aPoint "Answer whether the receiver is neither above nor to the left of aPoint." ^self x >= aPoint x and: [self y >= aPoint y]! hash "Hash is reimplemented because = is implemented." ^(self x hash bitShift: 2) bitXor: self y hash! isAllZero ^ (self x = 0) & (self y = 0) ! isZeroPt ^ self x = 0 and: [self y = 0] ! max: aPoint "Answer the lower right corner of the rectangle uniquely defined by the receiver and the argument, aPoint." ^ (self x max: aPoint x) @ (self y max: aPoint y)! min: aPoint "Answer the upper left corner of the rectangle uniquely defined by the receiver and the argument, aPoint." ^ (self x min: aPoint x) @ (self y min: aPoint y)! ! !Point methodsFor: 'arithmetic'! * scale "Answer a Point that is the product of the receiver and scale (which is a Point or Number)." | scalePoint | scalePoint _ scale asPoint. ^self x * scalePoint x @ (self y * scalePoint y)! + delta "Answer a Point that is the sum of the receiver and delta (which is a Point or Number)." | deltaPoint | deltaPoint _ delta asPoint. ^self x + deltaPoint x @ (self y + deltaPoint y)! - delta "Answer a Point that is the difference of the receiver and delta (which is a Point or Number)." | deltaPoint | deltaPoint _ delta asPoint. ^self x - deltaPoint x @ (self y - deltaPoint y)! / scale "Answer a Point that is the quotient of the receiver and scale (which is a Point or Number)." | scalePoint | scalePoint _ scale asPoint. ^self x / scalePoint x @ (self y / scalePoint y)! // scale "Answer a Point that is the quotient of the receiver and scale (which is a Point or Number)." | scalePoint | scalePoint _ scale asPoint. ^self x // scalePoint x @ (self y // scalePoint y)! abs "Answer a Point whose x and y are the absolute values of the receiver's x and y." ^ self x abs @ self y abs! ! !Point methodsFor: 'truncation and round off'! rounded "Answer a Point that is the receiver's x and y rounded." ^self x rounded @ self y rounded! truncated "Answer a Point that is the receiver's x and y truncated by removing the fractional part." ^(self x truncated) @ (self y truncated)! truncateTo: grid "Answer a Point that is the receiver's x and y truncated to grid x and grid y." | gridPoint | gridPoint _ grid asPoint. ^(self x truncateTo: gridPoint x) @ (self y truncateTo: gridPoint y)! ! !Point methodsFor: 'polar coordinates'! theta "Answer the angle the receiver makes with origin in radians. right is 0; down is 90." | tan theta | self x = 0 ifTrue: [self y >= 0 ifTrue: [^1.5708"90.0 degreesToRadians"] ifFalse: [^4.71239"270.0 degreesToRadians"]] ifFalse: [tan _ self y asFloat / self x asFloat. theta _ tan arcTan. self x >= 0 ifTrue: [self y >= 0 ifTrue: [^theta] ifFalse: [^360.0 degreesToRadians + theta]] ifFalse: [^180.0 degreesToRadians + theta]]! ! !Point methodsFor: 'point functions'! flipBy: direction centerAt: c "Answer a Point which is receiver flipped according to the direction, either #vertical or #horizontal, center at point c" ^ direction == #vertical ifTrue: [self x @ (c y * 2 - self y)] ifFalse: [(c x * 2 - self x) @ self y]! grid: aPoint "Answer a Point to the nearest rounded grid modules specified by aPoint." | newX newY | newX _ self x + (aPoint x // 2) truncateTo: aPoint x. newY _ self y + (aPoint y // 2) truncateTo: aPoint y. ^newX @ newY! isRectilinear: aPoint "Answer true if a line between the receiver and aPoint is either vertical or horizontal, else false" ^ (self x == aPoint x) | (self y == aPoint y)! nearestPointAlongLineFrom: p1 to: p2 "Note this will give points beyond the endpoints!!" "There may be a simpler way; I just followed algebra - Dan I." | x1 y1 x2 y2 x21 y21 xx yy y4 x4 | p1 x = p2 x ifTrue: [^ p1 x @ self y]. "vertical line" p1 y = p2 y ifTrue: [^ self x @ p1 y]. "horizontal line" x1 _ p1 x asFloat. y1 _ p1 y asFloat. x2 _ p2 x asFloat. y2 _ p2 y asFloat. x21 _ x2 - x1. y21 _ y2 - y1. xx _ x21 * x21. yy _ y21 * y21. y4 _ ((y2*xx) + (self y*yy) - ((x2-self x) * y21 * x21))/(xx + yy). x4 _ self x - ((y4-self y) * y21 / x21). ^ x4 @ y4 " | p | Pen new place: 0@0; goto: 500@300. [Sensor anyButtonPressed] whileFalse: [p _ Sensor cursorPoint nearestPointAlongLineFrom: 0@0 to: 500@300. 2 timesRepeat: [Display reverse: (p extent: 10@10)]] " ! normal "Answer a Point representing the unit vector rotated 90 deg clockwise." | n | n _ self y negated @ self x. ^n / (n x * n x + (n y * n y)) sqrt! octantOf: otherPoint "Return 1..8 indicating relative direction to otherPoint. 1=ESE, 2=SSE, ... etc. clockwise to 8=ENE" | quad moreHoriz | (self x = otherPoint x and: [self y > otherPoint y]) ifTrue: [^ 6]. "special case" (self y = otherPoint y and: [self x < otherPoint x]) ifTrue: [^ 8]. quad _ self quadrantOf: otherPoint. moreHoriz _ (self x - otherPoint x) abs >= (self y - otherPoint y) abs. (quad even eqv: moreHoriz) ifTrue: [^ quad*2] ifFalse: [^ quad*2 - 1]! quadrantOf: otherPoint "Return 1..4 indicating relative direction to otherPoint. 1 is downRight, 2=downLeft, 3=upLeft, 4=upRight" ^ self x <= otherPoint x ifTrue: [self y <= otherPoint y ifTrue: [1] ifFalse: [4]] ifFalse: [self y <= otherPoint y ifTrue: [2] ifFalse: [3]] ! transpose "Answer a Point whose x is the receiver's y and whose y is the receiver's x." ^self y @ self x! truncatedGrid: aPoint "Answer a Point to the nearest truncated grid modules specified by aPoint." ^(self x truncateTo: aPoint x) @ (self y truncateTo: aPoint y)! ! !Point methodsFor: 'converting'! asHeading "Treating the receiver as a velocity (with negative y meaning up for the time being), return the heading, in degrees, represented. Returns an integer result in the range [0, 359] 5/13/96 sw" | ans | self x == 0 ifTrue: [^ self y > 0 ifTrue: [180] ifFalse: [0]]. ans _ (90 + ((self y asFloat / self x) arcTan radiansToDegrees rounded)) \\ 360. ^ self x > 0 ifTrue: [ans] ifFalse: [ans + 180] " Array with: (10 @ 10) asHeading with: (10 @ -10) asHeading with: (-10 @ 10) asHeading with: (-10 @ -10) asHeading"! asIntegerPoint ^ self x asInteger @ self y asInteger! ! !Point methodsFor: 'transforming'! adhereTo: aRectangle "If the receiver lies outside aRectangle, it is mapped to the nearest point on the boundary of the rectangle" | nx ny | nx _ self x. ny _ self y. nx < aRectangle left ifTrue: [nx _ aRectangle left] ifFalse: [nx > aRectangle right ifTrue: [nx _ aRectangle right]]. ny < aRectangle top ifTrue: [ny _ aRectangle top] ifFalse: [ny > aRectangle bottom ifTrue: [ny _ aRectangle bottom]]. ^nx @ ny! negated "Answer a point whose x and y coordinates are the negatives of those of the receiver. 6/6/96 sw" ^ self x negated @ self y negated! scaleBy: factor "Answer a Point scaled by factor (an instance of Point)." ^(factor x * self x) @ (factor y * self y)! translateBy: delta "Answer a Point translated by delta (an instance of Point)." ^(delta x + self x) @ (delta y + self y)! ! !Point methodsFor: 'copying'! copy "Implemented here for better performance." ^ self x @ self y! deepCopy "Implemented here for better performance." ^self x deepCopy @ self y deepCopy! shallowCopy "Implemented here for better performance." ^ self x @ self y! ! !Point methodsFor: 'printing'! printOn: aStream "The receiver prints on aStream in terms of infix notation." self x printOn: aStream. aStream nextPut: $@. self y printOn: aStream! ! !Point methodsFor: 'MacApp'! at: aCoordSymbol put: value (aCoordSymbol == #y or: [aCoordSymbol == #v]) ifTrue: [self y: value. ^value]. (aCoordSymbol == #x or: [aCoordSymbol == #h]) ifTrue: [self x: value. ^value]. ^self error: 'Unknown coordinate symbol: ', aCoordSymbol printString ! h ^self x ! v ^self y ! ! SmallPoint comment: 'This class represents immediate Point objects. Because points with positive coordinates seem to be much more common, the range of supported values for x and y is not symmetrical, but biased to be -4096..12287'! !SmallPoint reorganize! ('accessing' setX:setY: x x: y y:) ! !SmallPoint methodsFor: 'accessing'! setX: xPoint setY: yPoint ^self error: 'immediate object'! x ^((self immediateValue bitShift: -16) bitAnd: 16383) - 4096! x: aNumber ^self error: 'immediate object'! y ^((self immediateValue bitShift: -2) bitAnd: 16383) - 4096! y: aNumber ^self error: 'immediate object'! ! !SmallPoint class methodsFor: 'instance creation'! x: x y: y ^self newWithImmediateValue: (x + 4096 bitShift: 16) + (y + 4096 bitShift: 2) + 1! ! !SmallPoint class methodsFor: 'class initialization'! initialize "SmallPoint initialize" "Register the class for Immediate class access" | cca | cca _ Smalltalk compactClassesArray. cca size = 47 ifFalse: [Smalltalk recreateSpecialObjectsArray. cca _ Smalltalk compactClassesArray]. 0 to: 3 do: [:i | cca at: 32+ (i * 4 + 1) put: self]! ! SmallPoint initialize!