From VisualWorks® NonCommercial, 7.4 of December 5, 2005 on January 28, 2006 at 6:34:42 am
Katachi
Smalltalk
false
private Smalltalk.*
Katachi
Katachi
KatachiWave
Smalltalk
Core.Object
false
none
figure eyeCatchers
Katachi
Katachi
Katachi2dWave
Smalltalk
KatachiWave
false
none
minimalEnclosingCircle samplingFrequency intensitySamples
Katachi
Katachi
Katachi2dHalfCircumferenceWave
Smalltalk
Katachi2dWave
false
none
Katachi
Katachi
Katachi2dReverseCircleWave
Smalltalk
Katachi2dWave
false
none
Katachi
Katachi
Katachi2dCircleWave
Smalltalk
Katachi2dWave
false
none
Katachi
Katachi
Katachi2dNullWave
Smalltalk
Katachi2dWave
false
none
Katachi
Katachi
Katachi2dPolygonWave
Smalltalk
Katachi2dWave
false
none
Katachi
Katachi
KatachiWave utilities
show
^self subclassResponsibility
KatachiWave initialize-release
initialize
eyeCatchers := OrderedCollection new.
^self
KatachiWave accessing
removeEyeCatcher: aPoint
eyeCatchers remove: aPoint
eyeCatchers
^eyeCatchers
addEyeCatcher: aPoint
eyeCatchers add: aPoint
figure
^figure
addEyeCatchers: aCollection
aCollection do: [:eyeCatcher | self addEyeCatcher: eyeCatcher]
removeEyeCatchers: aCollection
aCollection do: [:eyeCatcher | self removeEyeCatcher: eyeCatcher]
KatachiWave comparing
similarTo: aKatachiWave
"Return similarity between 0.0d and 1.0d."
^self subclassResponsibility
KatachiWave private
interpretFigure: figureRepresentation
^self subclassResponsibility
setFigure: figureRepresentation
figure := figureRepresentation.
self interpretFigure: figureRepresentation.
^self
Katachi2dWave class utilities
similarityMatrix: figureCollection
"
| kCollection |
kCollection := OrderedCollection new.
kCollection add: Katachi2dPolygonWave example1.
kCollection add: Katachi2dPolygonWave example2.
kCollection add: Katachi2dPolygonWave example3.
Katachi2dWave similarityMatrix: kCollection
"
| borderColor borderThickness paddingThickness headerBorderThickness cellExtent itemExtent headerRowHeight headerColumnWidth numberOfFigures originX1 originY1 extentX extentY extent image borderGc cellGc slashGc line figure atX atY baseFigure objectFigure similarityDescription similarity phase model textFont textWidth computeSimilarities similarityAccuracy roundedSimilarity text |
borderColor := ColorValue black.
borderThickness := 1.
paddingThickness := 3.
headerBorderThickness := 2.
cellExtent := 60 @ 78.
similarityAccuracy := 0.001d.
itemExtent := cellExtent - (paddingThickness * 2 asPoint).
headerRowHeight := cellExtent x.
headerColumnWidth := cellExtent x * 2.
numberOfFigures := figureCollection size.
originX1 := borderThickness + headerColumnWidth + headerBorderThickness.
originY1 := borderThickness + headerRowHeight + headerBorderThickness.
extentX := (cellExtent x + borderThickness) * numberOfFigures + originX1.
extentY := (cellExtent y + borderThickness) * numberOfFigures + originY1.
extent := extentX @ extentY.
cellGc := nil.
computeSimilarities := [:progress |
textFont := cellGc font.
1 to: numberOfFigures do: [:iy |
baseFigure := figureCollection at: iy.
atY := (cellExtent y + borderThickness) * (iy - 1) + originY1 + paddingThickness.
1 to: numberOfFigures do: [:ix |
progress message: ix printString, '@', iy printString.
progress value: (iy - 1) * numberOfFigures + ix - 1 / numberOfFigures squared.
objectFigure := figureCollection at: ix.
atX := (cellExtent x + borderThickness) * (ix - 1) + originX1 + paddingThickness.
similarityDescription := baseFigure similarTo: objectFigure.
similarity := similarityDescription at: 1.
roundedSimilarity := ((similarity / similarityAccuracy) rounded * similarityAccuracy) asFloat.
phase := similarityDescription at: 2.
image := objectFigure figureImageExtent: itemExtent - (0 @ textFont height) rotatePhase: phase.
cellGc displayImage: image at: atX @ atY.
text := roundedSimilarity printString.
textWidth := cellGc widthOfString: text.
cellGc displayString: text at: (atX + ((itemExtent x - textWidth) quo: 2)) @ (atY + itemExtent y - textFont descent)]]].
image := JunImageUtility imageExtent: extent
displayBlock: [:graphicsContext |
borderGc := graphicsContext copy.
cellGc := graphicsContext copy.
borderGc lineWidth: 1.
borderGc paint: borderColor.
line := Rectangle origin: Point zero extent: extent x @ borderThickness.
line displayFilledOn: borderGc.
line := Rectangle origin: Point zero extent: borderThickness @ extent y.
line displayFilledOn: borderGc.
line := Rectangle origin: 0 @ (borderThickness + headerRowHeight) extent: extent x @ headerBorderThickness.
line displayFilledOn: borderGc.
line := Rectangle origin: (borderThickness + headerColumnWidth) @ 0 extent: headerBorderThickness @ extent y.
line displayFilledOn: borderGc.
atX := borderThickness + headerColumnWidth.
atY := borderThickness + headerRowHeight.
slashGc := borderGc copy.
slashGc lineWidth: headerBorderThickness.
slashGc displayLineFrom: Point zero to: atX @ atY.
textFont := slashGc font.
text := 'base(self)'.
textWidth := slashGc widthOfString: text.
atX := borderThickness + paddingThickness.
atY := borderThickness + headerRowHeight - paddingThickness - textFont descent.
slashGc displayString: text at: atX @ atY.
text := 'compare to'.
textWidth := slashGc widthOfString: text.
atX := borderThickness + headerColumnWidth - paddingThickness - textWidth.
atY := borderThickness + paddingThickness + textFont ascent.
slashGc displayString: text at: atX @ atY.
1 to: numberOfFigures do: [:ix |
figure := figureCollection at: ix.
image := figure figureImageExtent: (cellExtent x @ headerRowHeight) - (paddingThickness * 2 asPoint).
atX := (cellExtent x + borderThickness) * (ix - 1) + originX1 + paddingThickness.
atY := borderThickness + paddingThickness.
cellGc displayImage: image at: atX @ atY.
atX := (cellExtent x + borderThickness) * (ix - 1) + originX1 + cellExtent x.
line := Rectangle origin: atX @ 0 extent: borderThickness @ extent y.
line displayFilledOn: borderGc].
1 to: numberOfFigures do: [:iy |
figure := figureCollection at: iy.
image := figure showImageExtent: (headerColumnWidth @ cellExtent y) - (paddingThickness * 2 asPoint).
atX := borderThickness + paddingThickness.
atY := (cellExtent y + borderThickness) * (iy - 1) + originY1 + paddingThickness.
cellGc displayImage: image at: atX @ atY.
atY := (cellExtent y + borderThickness) * (iy - 1) + originY1 + cellExtent y.
line := Rectangle origin: 0 @ atY extent: extent x @ borderThickness.
line displayFilledOn: borderGc].
JunProgress new do: [:progress | computeSimilarities value: progress]].
model := JunImageDisplayModel show: image
label: 'Katachi similarity matrix'.
^model
Katachi2dWave class examples
example2
"Katachi2dWave example2"
| kCollection |
kCollection := OrderedCollection new.
kCollection add: (Katachi2dPolygonWave regularPolygon: 3).
kCollection add: (Katachi2dPolygonWave regularPolygon: 4).
kCollection add: (Katachi2dPolygonWave regularPolygon: 6).
kCollection add: (Katachi2dPolygonWave stellatedPolygon: 5).
kCollection add: Katachi2dPolygonWave exampleBar.
kCollection add: Katachi2dPolygonWave exampleButterfly.
kCollection add: Katachi2dPolygonWave exampleCup.
kCollection add: Katachi2dPolygonWave exampleDeceivingCup.
kCollection add: Katachi2dPolygonWave exampleRightIsoscelesTriangle1.
kCollection add: Katachi2dPolygonWave exampleRightIsoscelesTriangle2.
kCollection add: Katachi2dPolygonWave exampleShell.
kCollection add: Katachi2dCircleWave new.
kCollection add: Katachi2dHalfCircumferenceWave new.
kCollection add: Katachi2dNullWave new.
kCollection add: Katachi2dReverseCircleWave new.
Katachi2dWave similarityMatrix: kCollection
example1
"Katachi2dWave example1"
| kCollection |
kCollection := OrderedCollection new.
kCollection add: (Katachi2dPolygonWave regularPolygon: 3).
kCollection add: (Katachi2dPolygonWave stellatedPolygon: 5).
kCollection add: Katachi2dPolygonWave exampleBar.
kCollection add: Katachi2dPolygonWave exampleCup.
kCollection add: Katachi2dPolygonWave exampleButterfly.
kCollection add: Katachi2dPolygonWave exampleRightIsoscelesTriangle1.
kCollection add: Katachi2dCircleWave new.
Katachi2dWave similarityMatrix: kCollection
Katachi2dWave utilities
show
^self showExtent: 400 @ 200
showWave
| waveImage model |
waveImage := self waveImageExtent: 200 @ 200.
model := JunImageDisplayModel show: waveImage
label: 'Wave of Katachi'.
^model
showFigure
| figureImage model |
figureImage := self figureImageExtent: 200 @ 200.
model := JunImageDisplayModel show: figureImage
label: 'Base figure of Katachi'.
^model
Katachi2dWave initialize-release
initialize
super initialize.
samplingFrequency := self defaultSamplingFrequency.
intensitySamples := nil.
^self
Katachi2dWave accessing
collectSamples: frequency
"Return an array whose size is (1 + frequency). The last element is same as the first one."
self samplingFrequency = frequency ifTrue: [^self intensitySamples].
^self rawCollectSamples: frequency
samplingFrequency
^samplingFrequency
eyeCatchedPhases
"Phases from where an eyeCatcher comes in your sight when you look at the center of the minimal enclosing circle."
| phases center |
phases := Set new: self eyeCatchers size.
center := minimalEnclosingCircle center.
self eyeCatchers do:
[:eyeCatcher |
(eyeCatcher equal: center)
ifFalse: [phases add: (eyeCatcher - center) theta deg / 360]].
^phases
intensitySamples
"Return an array whose size is (1 + samplingFrequency). The last element is same as the first one."
intensitySamples isNil
ifTrue: [intensitySamples := self rawCollectSamples: self samplingFrequency].
^intensitySamples copy
samplingFrequency: aPositiveInteger
aPositiveInteger = samplingFrequency
ifFalse:
[samplingFrequency := aPositiveInteger.
intensitySamples := nil].
self interpretFigure: self figure.
^samplingFrequency
intensityAt: phase
| index floor ceiling samples dIntensity floorIntensity ceilingIntensity |
index := (phase * self samplingFrequency) + 1.
floor := index floor.
ceiling := index ceiling.
samples := self intensitySamples.
floorIntensity := samples at: floor.
index = floor ifTrue: [^floorIntensity].
ceilingIntensity := samples at: ceiling.
dIntensity := ceilingIntensity - floorIntensity.
^(index - floor) * dIntensity + floorIntensity.
Katachi2dWave comparing
similarTo: aKatachi2dWave
"
Return an Array having 2 elements.
Its first element means similarity.
The second one means best rotation of aKatachi2dWave giving the similarity.
"
| waveComparisonMethod |
waveComparisonMethod := #(#RMS #abs) at: 1.
"waveComparisonMethod := #(#RMS #abs) at: 2."
waveComparisonMethod = #RMS ifTrue: [^self similarRMSDiffTo: aKatachi2dWave].
waveComparisonMethod = #Abs ifTrue: [^self similarAbsDiffTo: aKatachi2dWave].
self error: 'Illegal similarity strategy'.
similarRevolveRMSDiffTo: aKatachi2dWave
"Similarity with revolving strategy in terms of RMS(root mean square) diff of the two waves."
| compareFrequency diffSum mySamples hisSamples diffMax similarity similarityMax similarityMaxAt |
compareFrequency := self samplingFrequency.
mySamples := self intensitySamples.
hisSamples := aKatachi2dWave collectSamples: compareFrequency.
diffMax := 2 squared * compareFrequency.
similarityMax := -1.
0 to: compareFrequency - 1 do: [:rotateTick |
diffSum := 0.
self compare: [:p :q | diffSum := diffSum + (p - q) squared]
samples: mySamples
with: hisSamples
indexShift: rotateTick.
similarity := 1 - (diffSum / diffMax) sqrt.
similarity > similarityMax ifTrue: [
similarityMax := similarity.
similarityMaxAt := rotateTick]].
^Array with: similarityMax with: similarityMaxAt / compareFrequency
similarEyeCatchersAbsDiffTo: aKatachi2dWave
"Similarity with eye catcher strategy in terms of mean absolute diff of the two waves."
| compareFrequency diffSum mySamples myCatchedPhases revolvePhases hisCatchedPhases diffMax similarity similarityMax similarityMaxAt p q phase |
compareFrequency := self samplingFrequency.
mySamples := self intensitySamples.
myCatchedPhases := self eyeCatchedPhases.
hisCatchedPhases := aKatachi2dWave eyeCatchedPhases.
diffMax := 2 * compareFrequency.
similarityMax := -1.
revolvePhases := Set new: myCatchedPhases size * hisCatchedPhases size.
myCatchedPhases do: [:myCatchedPhase |
hisCatchedPhases do: [:hisCatchedPhase |
revolvePhases add: (myCatchedPhase - hisCatchedPhase) \\ 1.0]].
revolvePhases isEmpty ifTrue: [revolvePhases add: 0].
revolvePhases do: [:phaseShift |
diffSum := 0.
0 to: compareFrequency - 1 do: [:tick |
phase := tick / compareFrequency.
p := mySamples at: tick + 1.
q := aKatachi2dWave intensityAt: (phase - phaseShift) \\ 1.0.
diffSum := diffSum + (p - q) abs].
similarity := 1 - (diffSum / diffMax).
similarity > similarityMax ifTrue: [
similarityMax := similarity.
similarityMaxAt := phaseShift]].
^Array with: similarityMax with: similarityMaxAt
similarRMSDiffTo: aKatachi2dWave
"Similarity in terms of RMS(root mean square) diff of the two waves."
| revolveSimilarity eyeCatcherSimilarity |
revolveSimilarity := self similarRevolveRMSDiffTo: aKatachi2dWave.
eyeCatcherSimilarity := self similarEyeCatchersRMSDiffTo: aKatachi2dWave.
(revolveSimilarity at: 1) > (eyeCatcherSimilarity at: 1)
ifTrue: [^revolveSimilarity]
ifFalse: [^eyeCatcherSimilarity]
similarEyeCatchersRMSDiffTo: aKatachi2dWave
"Similarity with eye catcher strategy in terms of RMS(root mean square) diff of the two waves."
| compareFrequency diffSum mySamples myCatchedPhases revolvePhases hisCatchedPhases diffMax similarity similarityMax similarityMaxAt p q phase |
compareFrequency := self samplingFrequency.
mySamples := self intensitySamples.
myCatchedPhases := self eyeCatchedPhases.
hisCatchedPhases := aKatachi2dWave eyeCatchedPhases.
diffMax := 2 squared * compareFrequency.
similarityMax := -1.
revolvePhases := Set new: myCatchedPhases size * hisCatchedPhases size.
myCatchedPhases do: [:myCatchedPhase |
hisCatchedPhases do: [:hisCatchedPhase |
revolvePhases add: (myCatchedPhase - hisCatchedPhase) \\ 1.0]].
revolvePhases isEmpty ifTrue: [revolvePhases add: 0].
revolvePhases do: [:phaseShift |
diffSum := 0.
0 to: compareFrequency - 1 do: [:tick |
phase := tick / compareFrequency.
p := mySamples at: tick + 1.
q := aKatachi2dWave intensityAt: (phase - phaseShift) \\ 1.0.
diffSum := diffSum + (p - q) squared].
similarity := 1 - (diffSum / diffMax) sqrt.
similarity > similarityMax ifTrue: [
similarityMax := similarity.
similarityMaxAt := phaseShift]].
^Array with: similarityMax with: similarityMaxAt
similarAbsDiffTo: aKatachi2dWave
"Similarity in terms of mean absolute diff of the two waves."
| revolveSimilarity eyeCatcherSimilarity |
revolveSimilarity := self similarRevolveAbsDiffTo: aKatachi2dWave.
eyeCatcherSimilarity := self similarEyeCatchersAbsDiffTo: aKatachi2dWave.
(revolveSimilarity at: 1) > (eyeCatcherSimilarity at: 1)
ifTrue: [^revolveSimilarity]
ifFalse: [^eyeCatcherSimilarity]
similarRevolveAbsDiffTo: aKatachi2dWave
"Similarity with revolving strategy in terms of mean absolute diff of the two waves."
| compareFrequency diffSum mySamples hisSamples diffMax similarity similarityMax similarityMaxAt |
compareFrequency := self samplingFrequency.
mySamples := self intensitySamples.
hisSamples := aKatachi2dWave collectSamples: compareFrequency.
diffMax := 2 * compareFrequency.
similarityMax := -1.
0 to: compareFrequency - 1 do: [:rotateTick |
diffSum := 0.
self compare: [:p :q | diffSum := diffSum + (p - q) abs]
samples: mySamples
with: hisSamples
indexShift: rotateTick.
similarity := 1 - (diffSum / diffMax).
similarity > similarityMax ifTrue: [
similarityMax := similarity.
similarityMaxAt := rotateTick]].
^Array with: similarityMax with: similarityMaxAt / compareFrequency
Katachi2dWave private
defaultSamplingFrequency
^256
showImageExtent: extent
| showImage waveImage figureImage waveExtent waveOrigin figureExtent figureOrigin margin |
margin := 2.
waveOrigin := margin @ margin.
waveExtent := (extent x - margin - margin - margin / 2) @ (extent y - margin - margin).
figureOrigin := (margin + waveExtent x + margin) @ margin.
figureExtent := waveExtent.
waveExtent := waveExtent floor.
figureExtent := figureExtent floor.
waveImage := self waveImageExtent: waveExtent.
figureImage := self figureImageExtent: figureExtent.
showImage := JunImageUtility imageExtent: extent
displayBlock: [:gc |
gc displayImage: waveImage at: waveOrigin.
gc displayImage: figureImage at: figureOrigin].
^showImage
minimalEnclosingCircleOf: aJun2dPolygon
^self subclassResponsibility
rawCollectSamples: frequency
| samples phase intensityValue |
samples := Array new: (frequency + 1) asInteger.
1 to: samples size do: [:index |
phase := (index - 1) / frequency.
intensityValue := self depthAt: phase.
samples at: index put: intensityValue].
^samples
waveImageExtent: extent
| revolutionDirection phaseOffset axisColor waveColor waveThickness samples samplingFreq samplesRotateOffset rotatedSamples chart chartData |
revolutionDirection := 1.
phaseOffset := JunAngle fromDeg: 90.
axisColor := ColorValue blue.
waveColor := ColorValue purple.
waveThickness := 1.
samples := self intensitySamples.
samplingFreq := self samplingFrequency.
"self assert: [samplingFreq + 1 = samples size]."
samplesRotateOffset := (samplingFreq * phaseOffset uniformed deg / 360)
rounded.
rotatedSamples := self rotateIntensitySamples: samples
openingIndexAt: 1 + samplesRotateOffset.
revolutionDirection sign < 0
ifTrue: [rotatedSamples := rotatedSamples reverse].
chartData := rotatedSamples collect: [:intensity | Array with: intensity].
chart := JunChartLine sample: chartData.
chart valueRangeFrom: 0 to: 2.
chart axisColor: axisColor.
chart colors: (Array with: waveColor).
chart lineWidth: waveThickness.
chart showXAxis.
chart showYAxis.
chart fit.
^chart asImageExtent: extent
depthAt: phase
^self subclassResponsibility
showExtent: extent
| showImage model |
showImage := self showImageExtent: extent.
model := JunImageDisplayModel show: showImage
label: 'Katachi and its wave'.
^model
compare: compareBlock samples: baseSamples with: objectSamples indexShift: indexShift
| compareSize rotatedObjectSamples |
compareSize := self samplingFrequency.
indexShift = 0
ifTrue: [rotatedObjectSamples := objectSamples]
ifFalse:
[rotatedObjectSamples := self rotateIntensitySamples: objectSamples
openingIndexAt: compareSize + 1 - indexShift].
1 to: compareSize
do:
[:index |
compareBlock value: (baseSamples at: index)
value: (rotatedObjectSamples at: index)]
"
| compareSize |
compareSize := self samplingFrequency.
1 to: compareSize do: [:index |
compareBlock
value: (baseSamples at: index)
value: (objectSamples at: (index - 1 - indexShift) \\ compareSize + 1)]
"
figureImageExtent: extent rotatePhase: rotatePhase
| rotateAngle figureColor figureImage scale mecCenter imageCenter fitToImage mecRepresentation figureRepresentation tMoveToZero tResize tRotatePhaseOffset tAdaptImageCoordinate tMoveToImageCenter |
rotateAngle := JunAngle fromDeg: 360 * rotatePhase.
figureColor := ColorValue purple.
figureImage := JunImageUtility imageExtent: extent.
scale := (extent x min: extent y) / minimalEnclosingCircle radius / 2.
mecCenter := minimalEnclosingCircle center.
imageCenter := extent / 2.
tMoveToZero := Jun2dTransformation translate: mecCenter negated.
tResize := Jun2dTransformation scale: scale.
tRotatePhaseOffset := (Jun2dTransformation rotate: rotateAngle).
tAdaptImageCoordinate := Jun2dTransformation mirrorY.
tMoveToImageCenter := Jun2dTransformation translate: imageCenter.
fitToImage := (((tMoveToZero product: tResize) product: tRotatePhaseOffset) product: tAdaptImageCoordinate) product: tMoveToImageCenter.
figureRepresentation := figure transform: fitToImage.
mecRepresentation := minimalEnclosingCircle transform: fitToImage.
figureImage := JunImageUtility imageExtent: extent
displayBlock:
[:gc |
(Circle center: mecRepresentation center radius: mecRepresentation radius)
displayStrokedOn: gc.
gc paint: figureColor.
figureRepresentation displayOn: gc.
self displayOpeningMarkerOn: gc center: mecRepresentation center radius: mecRepresentation radius rotatePhase: rotatePhase].
^figureImage
figureImageExtent: extent
^self figureImageExtent: extent rotatePhase: 0
rotateIntensitySamples: sampleCollection openingIndexAt: openingIndex
| size rotatedCollection latterHalfSize frequency |
openingIndex = 1 ifTrue: [^sampleCollection copy].
size := sampleCollection size.
frequency := size - 1.
rotatedCollection := sampleCollection species withSize: size.
latterHalfSize := frequency - (openingIndex - 1).
rotatedCollection replaceFrom: 1 to: latterHalfSize with: sampleCollection startingAt: openingIndex.
rotatedCollection replaceFrom: latterHalfSize + 1 to: frequency with: sampleCollection startingAt: 1.
rotatedCollection at: size put: (rotatedCollection at: 1).
^rotatedCollection
displayOpeningMarkerOn: graphicsContext center: center radius: radius rotatePhase: rotatePhase
| gc centerPoint openingMarkColor openingMarkThickness directionArrowRemoteness rotateAngle farPoint directionArrowOrigin directionArrowTip arrowOpenness head1Angle head2Angle |
openingMarkColor := ColorValue blue.
openingMarkThickness := 1.
directionArrowRemoteness := 0.7.
gc := graphicsContext copy.
centerPoint := center asPoint.
gc translateBy: centerPoint.
rotateAngle := Double pi * 2 * rotatePhase.
farPoint := rotateAngle sin negated @ rotateAngle cos negated * radius.
gc paint: openingMarkColor.
gc lineWidth: openingMarkThickness.
gc displayLineFrom: Point zero to: farPoint.
directionArrowOrigin := farPoint * directionArrowRemoteness.
gc translateBy: directionArrowOrigin.
directionArrowTip := ((rotateAngle cos negated) @ (rotateAngle sin)) * 10.
gc displayLineFrom: Point zero to: directionArrowTip.
gc translateBy: directionArrowTip.
arrowOpenness := 45 degreesToRadians.
head1Angle := rotateAngle + (arrowOpenness / 2).
head2Angle := rotateAngle - (arrowOpenness / 2).
gc displayLineFrom: Point zero to: (head1Angle cos @ head1Angle sin negated) * 7.
gc displayLineFrom: Point zero to: (head2Angle cos @ head2Angle sin negated) * 7
Katachi2dCircleWave class instance creation
new
^super new initialize
Katachi2dCircleWave initialize-release
initialize
super initialize.
figure := Jun2dCircle center: 0, 0 radius: 1.
minimalEnclosingCircle := Jun2dCircle center: 0, 0 radius: 1.
^self
Katachi2dCircleWave accessing
depthAt: phase
^0
Katachi2dCircleWave private
figureImageExtent: extent rotatePhase: rotatePhase
| figureColor figureImage mecCenter mecRepresentation figureRepresentation mecRadius |
figureColor := ColorValue purple.
mecCenter := extent / 2.
mecRadius := (extent x min: extent y) / 2.
figureImage := JunImageUtility imageExtent: extent
displayBlock:
[:gc |
mecRepresentation := Circle center: mecCenter radius: mecRadius.
figureRepresentation := Circle center: mecCenter radius: mecRadius.
mecRepresentation displayStrokedOn: gc.
gc paint: figureColor.
figureRepresentation displayFilledOn: gc.
self displayOpeningMarkerOn: gc center: mecCenter radius: mecRadius rotatePhase: rotatePhase].
^figureImage
Katachi2dReverseCircleWave class instance creation
new
"Return a wave representing a virtual figure whose depth from M.E.C. is always 2."
^super new initialize
Katachi2dReverseCircleWave initialize-release
initialize
super initialize.
figure := Jun2dCircle center: 0, 0 radius: -1.
minimalEnclosingCircle := Jun2dCircle center: 0, 0 radius: 1.
^self
Katachi2dReverseCircleWave accessing
depthAt: phase
^2
Katachi2dReverseCircleWave private
figureImageExtent: extent rotatePhase: rotatePhase
| figureColor figureImage mecCenter mecRepresentation mecRadius figureCenter figureRadius prickleRadius theta direction prickles arrowOpenness prickleOrigin prickleTip head1Angle head2Angle |
figureColor := ColorValue purple.
mecCenter := extent / 2.
mecRadius := (extent x min: extent y) / 2.
figureImage := JunImageUtility imageExtent: extent
displayBlock:
[:gc |
mecRepresentation := Circle center: mecCenter radius: mecRadius.
mecRepresentation displayStrokedOn: gc.
gc paint: figureColor.
figureCenter := mecCenter.
figureRadius := mecRadius - 1.
prickleRadius := figureRadius * 0.9.
(Circle center: figureCenter radius: figureRadius) displayStrokedOn: gc.
prickles := 20.
arrowOpenness := 30 degreesToRadians.
0 to: prickles - 1 do: [:tick |
theta := tick / prickles * Double pi * 2.
direction := theta cos @ theta sin.
prickleOrigin := direction * figureRadius + figureCenter.
prickleTip := direction * prickleRadius + figureCenter.
gc displayLineFrom: prickleOrigin to: prickleTip.
head1Angle := theta + (arrowOpenness / 2).
head2Angle := theta - (arrowOpenness / 2).
gc displayLineFrom: prickleTip to: (head1Angle cos @ head1Angle sin) * 5 + prickleTip.
gc displayLineFrom: prickleTip to: (head2Angle cos @ head2Angle sin) * 5 + prickleTip].
self displayOpeningMarkerOn: gc center: mecCenter radius: mecRadius rotatePhase: rotatePhase].
^figureImage
Katachi2dNullWave class instance creation
new
"Return a wave representing a virtual figure whose depth from M.E.C. is always 0."
^super new initialize
Katachi2dNullWave initialize-release
initialize
super initialize.
figure := Jun2dCircle center: 0, 0 radius: 0.
minimalEnclosingCircle := Jun2dCircle center: 0, 0 radius: 1.
^self
Katachi2dNullWave accessing
depthAt: phase
^1
Katachi2dNullWave private
figureImageExtent: extent rotatePhase: rotatePhase
| figureColor figureImage mecCenter mecRepresentation figureRepresentation mecRadius nullFigureSize |
nullFigureSize := 3.
figureColor := ColorValue purple.
mecCenter := extent / 2.
mecRadius := (extent x min: extent y) / 2.
figureImage := JunImageUtility imageExtent: extent
displayBlock:
[:gc |
mecRepresentation := Circle center: mecCenter radius: mecRadius.
figureRepresentation := Circle center: mecCenter radius: nullFigureSize.
mecRepresentation displayStrokedOn: gc.
gc paint: figureColor.
figureRepresentation displayFilledOn: gc.
self displayOpeningMarkerOn: gc center: mecCenter radius: mecRadius rotatePhase: rotatePhase].
^figureImage
Katachi2dHalfCircumferenceWave class instance creation
new
"Return a wave representing the real figure that have the most biggest average depth in all of real possible figures."
^super new initialize
Katachi2dHalfCircumferenceWave initialize-release
initialize
| division arcOuter arcInner theta thickness |
super initialize.
division := 64.
thickness := 0.001d.
arcOuter := Array new: division + 1.
arcInner := Array new: division + 1.
0 to: division do: [:i |
theta := (Double pi * 2) * i / division * 0.5d.
arcOuter at: i + 1 put: theta cos @ theta sin.
arcInner at: i + 1 put: (theta cos negated @ theta sin) * (1 - thickness)].
figure := Jun2dPolygon points: arcOuter, arcInner.
minimalEnclosingCircle := Jun2dCircle center: 0, 0 radius: 1.
^self
Katachi2dHalfCircumferenceWave accessing
depthAt: phase
phase <= 0.5 ifTrue: [^0] ifFalse:[^2]
Katachi2dHalfCircumferenceWave private
figureImageExtent: extent rotatePhase: rotatePhase
| figureColor figureImage mecCenter mecRepresentation figureRepresentation mecRadius thickness |
figureColor := ColorValue purple.
thickness := 2.
mecCenter := extent / 2.
mecRadius := (extent x min: extent y) / 2.
figureImage := JunImageUtility imageExtent: extent
displayBlock:
[:gc |
mecRepresentation := Circle center: mecCenter radius: mecRadius.
figureRepresentation := EllipticalArc boundingBox: mecRepresentation bounds startAngle: 180 sweepAngle: 180.
mecRepresentation displayStrokedOn: gc.
gc paint: figureColor.
gc lineWidth: thickness.
figureRepresentation displayStrokedOn: gc.
self displayOpeningMarkerOn: gc center: mecCenter radius: mecRadius rotatePhase: rotatePhase].
^figureImage
Katachi2dPolygonWave class examples
exampleButterfly
"Katachi2dPolygonWave exampleButterfly show"
| vertexes butterfly |
vertexes := OrderedCollection new.
vertexes add: 1, 1.
vertexes add: 0, 0.1.
vertexes add: -1, 1.
vertexes add: -1, -1.
vertexes add: 0, -0.1.
vertexes add: 1, -1.
butterfly := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: butterfly.
exampleBar
"A long rectangle resembling a bar."
"Katachi2dPolygonWave exampleBar show"
| vertexes bar |
vertexes := OrderedCollection new.
vertexes add: 0, 0.
vertexes add: 10, 0.
vertexes add: 10, 1.
vertexes add: 0, 1.
bar := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: bar.
exampleRightIsoscelesTriangle1
"A right isosceles triangle. Mirror image of exampleRightIsoscelesTriangle2"
"Katachi2dPolygonWave exampleRightIsoscelesTriangle1 show"
| vertexes triangle |
vertexes := OrderedCollection new.
vertexes add: 0, 0.
vertexes add: 1, 0.
vertexes add: 0, 1.
triangle := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: triangle.
exampleDeceivingCup
"A raised bottom cup."
"Katachi2dPolygonWave exampleDeceivingCup show"
"Katachi2dWave similarityMatrix: (Array with: Katachi2dPolygonWave exampleDeceivingCup with: Katachi2dPolygonWave exampleCup)"
| vertexes cup |
vertexes := OrderedCollection new.
vertexes add: 0, 0.
vertexes add: 100, 0.
vertexes add: 100, 100.
vertexes add: 90, 100.
vertexes add: 55, 50.
vertexes add: 82, 10.
vertexes add: 18, 10.
vertexes add: 45, 50.
vertexes add: 10, 100.
vertexes add: 0, 100.
cup := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: cup.
exampleCup
"Katachi2dPolygonWave exampleCup show"
"Katachi2dWave similarityMatrix: (Array with: Katachi2dPolygonWave exampleDeceivingCup with: Katachi2dPolygonWave exampleCup)"
| vertexes cup |
vertexes := OrderedCollection new.
vertexes add: 0, 0.
vertexes add: 100, 0.
vertexes add: 100, 100.
vertexes add: 90, 100.
vertexes add: 90, 10.
vertexes add: 10, 10.
vertexes add: 10, 100.
vertexes add: 0, 100.
cup := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: cup.
exampleShell
"Katachi2dPolygonWave exampleShell show"
| vertexes ticks theta r shell |
ticks := 10.
vertexes := OrderedCollection new.
0 to: ticks - 1 do: [:tick |
theta := Double pi * 2 * tick / ticks.
r := ticks - tick / ticks.
vertexes add: (theta cos , theta sin) * r].
shell := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: shell.
exampleRightIsoscelesTriangle2
"A right isosceles triangle. Mirror image of exampleRightIsoscelesTriangle1"
"Katachi2dPolygonWave exampleRightIsoscelesTriangle2 show"
| vertexes triangle |
vertexes := OrderedCollection new.
vertexes add: 0, 0.
vertexes add: -1, 0.
vertexes add: 0, 1.
triangle := Jun2dPolygon vertexes: vertexes asArray.
^Katachi2dPolygonWave fromPolygon: triangle.
Katachi2dPolygonWave class instance creation
fromPolygon: aJun2dPolygon
| newwave |
newwave := self new initialize.
newwave setFigure: aJun2dPolygon.
^newwave
stellatedPolygon: numberOfHorns
"(Katachi2dPolygonWave stellatedPolygon: 13) show"
| rightPolygonVertexes theta seed p1 p2 e1 e2 stellatedVertexes valleyRadius stellatedPolygon |
numberOfHorns odd ifFalse: [^nil].
numberOfHorns < 5 ifTrue: [^nil].
rightPolygonVertexes := Array new: numberOfHorns.
1 to: numberOfHorns do: [:i |
theta := i / numberOfHorns * Double pi * 2.
rightPolygonVertexes at: i put: theta cos @ theta sin].
seed := numberOfHorns - 1 / 2.
p1 := rightPolygonVertexes at: 1.
p2 := rightPolygonVertexes at: seed + 1.
e1 := Jun2dLine from: p1 to: p2.
p1 := rightPolygonVertexes at: 2.
p2 := rightPolygonVertexes at: seed + 3.
e2 := Jun2dLine from: p1 to: p2.
valleyRadius := (e1 intersectingPointWithLine: e2) rho.
stellatedVertexes := Array new: numberOfHorns * 2.
1 to: numberOfHorns do: [:i |
stellatedVertexes at: i * 2 - 1 put: (rightPolygonVertexes at: i).
theta := i + 0.5d / numberOfHorns * Double pi * 2.
stellatedVertexes at: i * 2 put: (theta cos @ theta sin) * valleyRadius].
stellatedPolygon := Jun2dPolygon points: stellatedVertexes.
^self fromPolygon: stellatedPolygon
regularPolygon: numberOfVertexes
"(Katachi2dPolygonWave regularPolygon: 3) show"
| vertexes theta polygon centralAngle |
numberOfVertexes < 3 ifTrue: [^nil].
vertexes := Array new: numberOfVertexes.
centralAngle := Double pi * 2 / numberOfVertexes.
1 to: numberOfVertexes do: [:i |
theta := centralAngle * i.
vertexes at: i put: theta cos @ theta sin].
polygon := Jun2dPolygon points: vertexes.
^self fromPolygon: polygon
Katachi2dPolygonWave private
depthAt: phase
| center radius viewPoint viewLine edge rawDepth sight sightRawDepth |
center := minimalEnclosingCircle center.
radius := minimalEnclosingCircle radius.
viewPoint:= center + (Jun2dPoint rho: radius theta: 2 * Double pi * phase).
viewLine := Jun2dLine from: viewPoint to: center.
rawDepth := nil.
figure edgesDo: [:point1 :point2 |
edge := Jun2dLine from: point1 to: point2.
sight := self edge: edge isVisibleOn: viewLine.
(sight isNil and: [edge containsPoint: viewPoint])
ifTrue: [sight := edge center].
sight isNil ifFalse: [
sightRawDepth := (sight - viewPoint) length.
rawDepth isNil
ifTrue: [rawDepth := sightRawDepth]
ifFalse: [rawDepth := rawDepth min: sightRawDepth]]].
^rawDepth isNil ifTrue: [^2] ifFalse: [^rawDepth / radius]
minimalEnclosingCircleOf: aJun2dPolygon
| bbox offset delaunay delaunayPoints delaunayExtent delaunayMEC |
bbox := aJun2dPolygon boundingBox.
offset := bbox origin.
delaunayPoints := aJun2dPolygon points
collect: [:vertex | vertex asPoint - offset].
delaunayExtent := bbox extent ceiling.
delaunay := JunDelaunay2dDiagram
extent: delaunayExtent x asInteger @ delaunayExtent y asInteger.
delaunay addAll: delaunayPoints.
delaunayMEC := delaunay minimalEnclosingCircle.
minimalEnclosingCircle := delaunayMEC translatedBy: offset.
^minimalEnclosingCircle
interpretFigure: aJun2dPolygon
self addEyeCatchers: aJun2dPolygon points.
minimalEnclosingCircle := self minimalEnclosingCircleOf: aJun2dPolygon
edge: segmentJun2dLine isVisibleOn: viewJun2dLine
| intersectingT |
intersectingT := segmentJun2dLine intersectingTWithLine: viewJun2dLine.
intersectingT isNil ifTrue: [^nil].
intersectingT < 0 ifTrue: [^nil].
intersectingT > 1 ifTrue: [^nil].
^segmentJun2dLine atT: intersectingT