home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BURKS 2
/
BURKS_AUG97.ISO
/
BURKS
/
LANGUAGE
/
SMALTALK
/
TEXTBOOK
/
AP24.ST
(
.txt
)
< prev
next >
Wrap
Text File
|
1997-04-22
|
12KB
|
518 lines
'Smalltalk Textbook Appendix 24'!
Object subclass: #EngiGeometric
instanceVariableNames: 'graphicsState cachedBounds '
classVariableNames: ''
poolDictionaries: ''
category: 'Engi-Geometric'!
EngiGeometric comment:
'
Engi 0.07 (24 March 1994)
Copyright (C) 1994 by Atsushi Aoki
'!
!EngiGeometric methodsFor: 'initialize-release'!
initialize
graphicsState := EngiGraphicsState new.
cachedBounds := nil.
^self! !
!EngiGeometric methodsFor: 'state accessing'!
fillColor
^graphicsState fillColor!
fillColor: colorValue
graphicsState fillColor: colorValue!
lineWidth
^graphicsState lineWidth!
lineWidth: anInteger
graphicsState lineWidth: anInteger.
self flushBounds!
strokeColor
^graphicsState strokeColor!
strokeColor: colorValue
graphicsState strokeColor: colorValue! !
!EngiGeometric methodsFor: 'bounds accessing'!
bounds
cachedBounds isNil ifTrue: [cachedBounds := self computeBounds].
^cachedBounds!
computeBounds
^self subclassResponsibility!
flushBounds
cachedBounds := nil! !
!EngiGeometric methodsFor: 'transforming'!
rotatedBy: angleDegree
^self subclassResponsibility!
scaledBy: scalePoint
^self subclassResponsibility!
translatedBy: amountPoint
^self subclassResponsibility! !
!EngiGeometric methodsFor: 'displaying'!
display
self displayAt: Point zero!
displayAt: aPoint
| graphicsContext |
graphicsContext := self class activeGraphicsContext.
self displayOn: graphicsContext at: aPoint!
displayFilledOn: graphicsContext at: aPoint
^self subclassResponsibility!
displayOn: graphicsContext
self displayOn: graphicsContext at: Point zero!
displayOn: graphicsContext at: aPoint
self lineWidth <= 0 ifTrue: [^self].
self fillColor notNil ifTrue: [self displayFilledOn: graphicsContext at: aPoint].
self strokeColor notNil ifTrue: [self displayStrokedOn: graphicsContext at: aPoint]!
displayStrokedOn: graphicsContext at: aPoint
^self subclassResponsibility! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
EngiGeometric class
instanceVariableNames: ''!
!EngiGeometric class methodsFor: 'circle utilities'!
containsPoint: j center: k radius: r
| xkj ykj xkjsq ykjsq denom root |
xkj := k x - j x.
ykj := k y - j y.
xkjsq := xkj * xkj.
ykjsq := ykj * ykj.
denom := xkjsq + ykjsq.
denom < self acc ifTrue: ["point(j) = center(k)"
^true].
root := denom - (r * r).
root < self acc negated ifTrue: ["point(j) is within circle(k, r)"
^true].
root < self acc ifTrue: ["point(j) touches circle(k, j)"
^true].
^false!
intersectFrom: k to: l center: j radius: r
| result f g fsq gsq fgsq xjk yjk fygx root fxgy box t1 x1 y1 p1 p2 fginv t2 x2 y2 |
result := OrderedCollection new.
f := l x - k x.
g := l y - k y.
fsq := f * f.
gsq := g * g.
fgsq := fsq + gsq.
fgsq < self acc ifTrue: [fgsq := self acc].
xjk := j x - k x.
yjk := j y - k y.
fygx := f * yjk - (g * xjk).
root := r * r * fgsq - (fygx * fygx).
root < self acc negated ifTrue: ["line(k, l) is without circle(j, r)"
^result].
fxgy := f * xjk + (g * yjk).
box := (k extent: 0 @ 0)
merge: (l extent: 0 @ 0).
root < self acc
ifTrue:
["line(k, l) touches circle(j, r)"
t1 := fxgy / fgsq.
x1 := k x + (f * t1).
y1 := k y + (g * t1).
p1 := x1 @ y1.
p2 := nil.
(self containsPoint: p1 inRectangle: box)
ifTrue: [result add: p1].
^result]
ifFalse:
["line(k, l) intersects circle(j, r)"
root := root sqrt.
fginv := 1.0 / fgsq.
t1 := fxgy - root * fginv.
x1 := k x + (f * t1).
y1 := k y + (g * t1).
p1 := x1 @ y1.
t2 := fxgy + root * fginv.
x2 := k x + (f * t2).
y2 := k y + (g * t2).
p2 := x2 @ y2.
(self containsPoint: p1 inRectangle: box)
ifTrue: [result add: p1].
(self containsPoint: p2 inRectangle: box)
ifTrue: [result add: p2].
^result]!
intersectsFrom: k to: l center: j radius: r
^(self
intersectFrom: k
to: l
center: j
radius: r) isEmpty not!
touchPoint: j center: k radius: r
| result xkj ykj xkjsq ykjsq denom root deninv a b x y |
result := OrderedCollection new.
xkj := k x - j x.
ykj := k y - j y.
xkjsq := xkj * xkj.
ykjsq := ykj * ykj.
denom := xkjsq + ykjsq.
denom < self acc ifTrue: ["point(j) = center(k)"
^result].
root := denom - (r * r).
root < self acc negated ifTrue: ["point(j) is within circle(k, r)"
^result].
deninv := 1.0 / denom.
root < self acc
ifTrue:
["point(j) touches circle(k, j)"
a := r negated * xkj * deninv.
b := r negated * ykj * deninv.
x := k x + (a * r).
y := k y + (b * r).
result add: x @ y]
ifFalse:
["point(j) is without circle(k, r)"
root := root sqrt.
a := r negated * xkj - (ykj * root) * deninv.
b := r negated * ykj + (xkj * root) * deninv.
x := k x + (a * r).
y := k y + (b * r).
result add: x @ y.
a := r * xkj - (ykj * root) * deninv.
b := r * ykj + (xkj * root) * deninv.
x := k x - (a * r).
y := k y - (b * r).
result add: x @ y].
^result! !
!EngiGeometric class methodsFor: 'constants utilities'!
acc
^1.0e-5! !
!EngiGeometric class methodsFor: 'line utilities'!
angleFrom: k to: l
| x y d |
x := l x - k x.
y := l y - k y.
x = 0 ifTrue: [x := self acc].
d := (y / x) arcTan radiansToDegrees.
(x positive and: [y positive])
ifTrue: [^d].
(x positive and: [y negative])
ifTrue: [^360.0 + d].
(x negative and: [y positive])
ifTrue: [^180.0 + d].
(x negative and: [y negative])
ifTrue: [^180.0 + d].
^d!
distance: j from: k to: l
| xkj ykj xlk ylk denom t xfac yfac |
xkj := k x - j x.
ykj := k y - j y.
xlk := l x - k x.
ylk := l y - k y.
denom := xlk * xlk + (ylk * ylk).
denom < self acc
ifTrue: [^(xkj * xkj + (ykj * ykj)) sqrt]
ifFalse:
[t := (xkj * xlk + (ykj * ylk)) negated / denom.
t := (t max: 0.0)
min: 1.0.
xfac := xkj + (t * xlk).
yfac := ykj + (t * ylk).
^(xfac * xfac + (yfac * yfac)) sqrt]!
intersectFrom: k to: l from: m to: n
| xlk ylk xnm ynm xmk ymk det detinv s t x y |
xlk := l x - k x.
ylk := l y - k y.
xnm := n x - m x.
ynm := n y - m y.
xmk := m x - k x.
ymk := m y - k y.
det := xnm * ylk - (ynm * xlk).
det abs < self acc ifTrue: [^nil].
detinv := 1.0 / det.
s := xnm * ymk - (ynm * xmk) * detinv.
t := xlk * ymk - (ylk * xmk) * detinv.
(s < 0.0 or: [s > 1.0])
ifTrue: [^nil].
(t < 0.0 or: [t > 1.0])
ifTrue: [^nil].
x := k x + (xlk * s).
y := k y + (ylk * s).
^x @ y!
intersectsFrom: k to: l from: m to: n
^(self
intersectFrom: k
to: l
from: m
to: n) notNil! !
!EngiGeometric class methodsFor: 'point utilities'!
adjacentPoints: aPoint
| adjacentPoints |
adjacentPoints := Array new: 8.
adjacentPoints at: 1 put: aPoint + (-1 @ -1).
adjacentPoints at: 2 put: aPoint + (0 @ -1).
adjacentPoints at: 3 put: aPoint + (1 @ -1).
adjacentPoints at: 4 put: aPoint + (1 @ 0).
adjacentPoints at: 5 put: aPoint + (1 @ 1).
adjacentPoints at: 6 put: aPoint + (0 @ 1).
adjacentPoints at: 7 put: aPoint + (-1 @ 1).
adjacentPoints at: 8 put: aPoint + (-1 @ 0).
^adjacentPoints!
coordinationNumber: aPoint
| x y |
x := aPoint x.
y := aPoint y.
(x >= 0 and: [y >= 0])
ifTrue: [^1].
(x < 0 and: [y >= 0])
ifTrue: [^2].
(x < 0 and: [y < 0])
ifTrue: [^3].
(x >= 0 and: [y < 0])
ifTrue: [^4].
self error: 'Unexpected point!!'!
coordinationNumber: aPoint originPoint: originPoint
^self coordinationNumber: aPoint - originPoint!
rotate: point by: degree
| radians sin cos x y |
radians := degree negated degreesToRadians.
sin := radians sin.
cos := radians cos.
x := point x * cos + (point y * sin).
y := point x * sin negated + (point y * cos).
^x @ y!
scale: point by: factor
^factor x * point x @ (factor y * point y)!
translate: point by: delta
^delta x + point x @ (delta y + point y)! !
!EngiGeometric class methodsFor: 'rectangle utilities'!
containsPoint: aPoint inRectangle: aRectangle
^aRectangle origin <= aPoint and: [aPoint <= aRectangle corner]!
containsPoint: j origin: o corner: c
^self containsPoint: j inRectangle: (Rectangle origin: o corner: c)!
containsPoint: j origin: o extent: e
^self containsPoint: j inRectangle: (Rectangle origin: o extent: e)!
intersectFrom: k to: l origin: o corner: c
| resu