'From Squeak3.9alpha of ''2 November 2004'' [latest update: #6532] on 11 January 2005 at 9:45:51 pm'! "Change Set: StarMorph-wiz Date: 11 December 2004 Author: wiz (Jerome Peace) with: Change Set: StarMorphPlus-wiz Date: 4 January 2005 Author: wiz (Jerome Peace) wiz 1/11/2005 21:44 Added insureCompatibility when adding handles. wiz 1/11/2005 20:52 Fixed menu bug with twinkle actions. wiz 1/11/2005 19:52 Modularized generation and separated the handling of handle groups. Updated Class comment. And handle balloon comments. wiz 1/11/2005 15:09 Another good stopping point. Added wrapping forms of prev/next. Modularized menu items for more/less prev/next. And made prev/next handles twinkle or not depending on the shift key. wiz 1/11/2005 13:46 The skipRatios are now producing the correct ratios. So this is a good save point. ToDo: Get next and previous handles to twinkle i.e. wrap. Give option of having 2, 4 or 6 handles up at a time. Outer/inner more/less next/prev. And fix up handle code to be more modular. Here are the additions to StarMorph-wiz to add the ability to adjust the stars shape. The theory is you should be able to get an accurate depiction of the skip stars this way. In practice, the starRatios don't seem to be accurate and too many round off errs seem to creep in with the floating point arithmetic. Still if I can find some accurate way of forming skip ratios its all done. wiz 12/30/2004 03:07 Extreme testing showed a bug at 360 sides. Corrected by adding precision to constant. Bug will show up at 360000 sides or there abouts. wiz 12/29/2004 00:27 Fixed spelling error in class comment. This is saved in 3.2 since I wanted to save a play-with-me backwardly compatible this far. Play with me loads in 3.8 (I checked). I presume it will load in everything before that. It also loads in 3.9 (with deprection error because of the system window for the workspace holding the text. wiz 12/19/2004 00:50 Hopefully the final changes have now been made. I found that to make my claims of backward compatability true I needed to fix one more bug. The vertices must be checked to insure the first vertex is a point not a valley. That done the adding the new handles to the old already formed stars works fine. wiz 12/15/2004 01:20 Fixed a hardly noticable bug that caused odd sided gons to look odd just after being changed. Now they will always look regular. And added handles to adjust the number of points and sides. Also mucked with their look. I'm rather pleased with the end result. This is an Enhancement for StarMorph. The enhancements do not change the old behavior of the StarMorph (except for the outer handle bug fix). The enhancements add some useful behavior that allows the StarMorph to generate stars with any number of points; control the pointyness of those stars; and generate any of the regular polygons. 1) The outer handle now stays where you put it. 2) Shift draging the outer handle now changes the pointiness of the star. 3) Custom menu items have been added to change the number of points. 4) Class comment has been added to explain features and changes. "! !StarMorph commentStamp: 'wiz 1/11/2005 17:04' prior: 0! I am a very flexible star.. Grab me from the supplies flap or from the graphic objects. Add my handles and you can move and resize me. The up and down arrows increase or reduce the number of my sides. The right and left arrows change to try out different amounts of pointiness. Use the arrows right and left of my center or get stars with a specific amount of pointyness. The left side goes from fat to thin and then cycles around again. The right goes from thin to fat. Hold down the shift key if you wish to stop the cycling. Use the arrows above and below my center or use the menu to change the number of sides if you would like a different number of points. To add or remove just one side hold the shift key down as you use the arrows or use the menu items for that purpose. If you add or remove just one point I will have an odd number of sides. When that happens I can only look like a regular polygon. Add or remove just one more side and you can shift drag the outer handle to restore my pointiness. At some time you will probably shift drag the outer handle thru the center handle. While I looked round as you shrunk me, I will look very much like an asterisk as you pull me away. What happens is that inside bend shrunk on the way down because it can never be larger than the outer point or it wouldn't be the innerbend would it. But on the way out it is perfectly happy to remain small. So I look like an asterisk. To fatten me up (if you haven't already figured this out by fooling around) is to hold the shift down an move the outer handle towards the center (but not quite all the way) then let the shift up and move the outer handle away. A couple of cycles like this and I'll be looking fat and jolly again. Or you can now just use the right arrow to make me fatter. This is also the reason I don't let the inside bend get larger than the outer point. If I did the same process that fattened me when I was an asterisk would also grow an asterisk so large squeak would complain about not having enough memory. Historical note: The former star had two bugs that are fixed here. The outer handle now no longer jumps from one point to another. The other bug prevented some higher order stars from looking right. Which is why the former star didn't allow you to change the number of points. ! !StarMorph methodsFor: 'editing' stamp: 'wiz 12/15/2004 00:59'! addHandles self addStarHandles! ! !StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 21:43'! addStarHandles "Outer handle must not be blocked so it comes first. The editing routine expects to find the center handle second. The side and shape changing handles follow these." | center | self removeHandles. "Check for old stars and correct order of vertices." self insureCompatability . handles := OrderedCollection new. center := vertices average rounded. self withCenterOuterHandles; withUpDownLeftRightHandlesAround: 6 center: center. self addAllMorphs: (handles first: 6). self changed! ! !StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:55'! changeVertices: label event: evt fromHandle: handle | | label == #more ifTrue: [evt shiftPressed ifTrue: [self oneMoreVertex] ifFalse: [self moreVertices]]. label == #less ifTrue: [evt shiftPressed ifTrue: [self oneLessVertex] ifFalse: [self lessVertices]]. label == #next ifTrue: [evt shiftPressed ifTrue: [self makeVertices: vertices size starRatio: self nextSkip] ifFalse: [self makeVertices: vertices size starRatio: self nextTwinkleSkip]]. label == #prev ifTrue: [evt shiftPressed ifTrue: [self makeVertices: vertices size starRatio: self prevSkip] ifFalse: [self makeVertices: vertices size starRatio: self prevTwinkleSkip]]. self computeBounds! ! !StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:57'! dragVertex: label event: evt fromHandle: handle | center r1 rN rNext a1 rTotal | label == #outside ifTrue: [center := handles second center. r1 := center dist: vertices first. rN := center dist: vertices last. rNext := 1 max: (center dist: evt cursorPoint). a1 := 270 + (center bearingToPoint: evt cursorPoint). rTotal := vertices size even ifTrue: [evt shiftPressed ifTrue: [rNext + rNext min: rNext + rN] ifFalse: [r1 + rN * rNext / r1]] ifFalse: [rNext + rNext]. rNext := rTotal - rNext. vertices := (a1 to: a1 + 359.999 by: 360.0 / vertices size) collect: [:angle | center + (Point r: (rNext := rTotal - rNext) degrees: angle)]. handle align: handle center with: evt cursorPoint]. label == #center ifTrue: [self position: self position + (evt cursorPoint - handle center)]. self computeBounds! ! !StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:39'! withCenterOuterHandles "Add to our handles the center positioning and outer resizing handles. Outer handle must not be blocked so it comes first. The editing routine expects to find the center handle second. The side and shape changing handles follow these." | center v1 hExtent holder | center := vertices average rounded. hExtent := 8 @ 8. v1 := vertices first. holder := {(EllipseMorph newBounds: (Rectangle center: v1 extent: hExtent) color: Color yellow) setBalloonText: 'Move me to adjust size. Shift move to adjust pointiness'. (EllipseMorph newBounds: (Rectangle center: center extent: hExtent) color: Color yellow) setBalloonText: 'Move me to adjust position'}. holder with: {#outside. #center} do: [:handle :which | handle on: #mouseDown send: #dragVertex:event:fromHandle: to: self withValue: which; on: #mouseMove send: #dragVertex:event:fromHandle: to: self withValue: which]. handles addAll: holder! ! !StarMorph methodsFor: 'editing' stamp: 'wiz 1/11/2005 19:47'! withUpDownLeftRightHandlesAround: radius center: center "Add to our handles the side and shape changing handles." | tri above holder triAbove triBelow triRight triLeft | above := 0 @ radius negated. tri := Array with: 0 @ -5 with: 4 @ 3 with: -4 @ 3. triAbove := tri + (center + above). triBelow := triAbove collect: [:pt | pt rotateBy: #pi centerAt: center]. triRight := triAbove collect: [:pt | pt rotateBy: #right centerAt: center]. triLeft := triAbove collect: [:pt | pt rotateBy: #left centerAt: center]. holder := { (PolygonMorph vertices: triAbove color: Color green borderWidth: 1 borderColor: Color black) setBalloonText: 'More points.'. (PolygonMorph vertices: triBelow color: Color magenta borderWidth: 1 borderColor: Color black) setBalloonText: 'Fewer points.'. (PolygonMorph vertices: triRight color: Color green borderWidth: 1 borderColor: Color black) setBalloonText: 'Twinkle fatter.'. (PolygonMorph vertices: triLeft color: Color magenta borderWidth: 1 borderColor: Color black) setBalloonText: 'Twinkle thinner.'}. holder with: {#more. #less. #next. #prev} do: [:handle :which | handle on: #mouseDown send: #changeVertices:event:fromHandle: to: self withValue: which; on: #mouseMove send: #changeVertices:event:fromHandle: to: self withValue: which]. ^ handles addAll: holder! ! !StarMorph methodsFor: 'accessing' stamp: 'wiz 1/4/2005 19:47'! starRatio: r "Set the star s.t. the ratio of the inner radius to the outer radius is r. If r is > 1 use the reciprocal to keep the outer radius first." "Assume we have at least one vertex. set All ways return a number <= 1.0" self makeVertices: vertices size starRatio:( r > 1.0 ifTrue: [ r reciprocal ] ifFalse: [r ] ).! ! !StarMorph methodsFor: 'geometry' stamp: 'wiz 1/4/2005 21:02'! nextSkip "Set starRatio to next higher skip" | skips oldR n | (oldR := self starRatio) >= 1.0 ifTrue: [ ^oldR ] . skips := self skipRatios . n := skips findFirst: [ :r | r > (oldR + 0.001) ] . n = 0 ifTrue: [ ^ oldR ] . ^ skips at: n . ! ! !StarMorph methodsFor: 'geometry' stamp: 'wiz 1/11/2005 15:02'! nextTwinkleSkip "Set starRatio to next skip wrapping if needed." | skips oldR n | oldR := self starRatio. ">= 1.0 ifTrue: [^ oldR]" skips := self skipRatios. n := skips findFirst: [:r | r > (oldR + 0.001)]. n = 0 ifTrue: [ n := 1]. ^ skips atWrap: n! ! !StarMorph methodsFor: 'geometry' stamp: 'wiz 1/4/2005 21:02'! prevSkip "Set starRatio to next higher skip" | skips oldR n | (oldR := self starRatio) <= 0.0 ifTrue: [ ^oldR ] . skips := self skipRatios . n := skips findLast: [ :r | r +0.001 < oldR ] . n = 0 ifTrue: [ ^ oldR ] . ^ skips at: n . ! ! !StarMorph methodsFor: 'geometry' stamp: 'wiz 1/11/2005 15:04'! prevTwinkleSkip "Set starRatio to next skip wrapping if necessary" | skips oldR n | (oldR := self starRatio) "<= 0.0 ifTrue: [^ oldR]". skips := self skipRatios. n := skips findLast: [:r | r + 0.001 < oldR]. " n = 0 ifTrue: [^ oldR]." ^ skips atWrap: n! ! !StarMorph methodsFor: 'access' stamp: 'wiz 1/11/2005 03:58'! skipRatios "Return an array of ratios of the inner radius to the outer radius. Ratios are in ascending order from 0.0 to 1.0." "Assume we have at least one vertex. All ways return a number <= 1.0" | n alpha | "Odd vertices sizes can not be stars only regular polygons" n:= vertices size . n odd ifTrue: [ ^ #( 1.0) ] . alpha := Float pi / (n//2) asFloat . ^ (((( Float halfPi -alpha to: alpha /2.0 by: alpha negated ) collect: [:angle |( (angle) sin )/ (angle + alpha ) sin ] ) copyWith: 0.0) copyWithFirst: 1.0) reversed .! ! !StarMorph methodsFor: 'access' stamp: 'wiz 1/4/2005 20:14'! starRatio "Return the ratio of the inner radius to the outer radius." "Assume we have at least one vertex. All ways return a number <= 1.0" | r c | c := vertices average rounded . r := (c dist: vertices last) / (c dist: vertices first) . ^ r > 1.0 ifTrue: [ r reciprocal ] ifFalse: [r ] .! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:33'! defaultCenter "answer the default center for the receiver" ^ 0 asPoint! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:33'! defaultFirstVertex "answer the default first outer point for the receiver. This with the center determines the angle and size of the outer radius." ^ 10 asPoint! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:28'! defaultSides "answer the default number of sides for the receiver" ^ 10! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:29'! defaultStarRatio "answer the default ratio of outer radius to inner radius for the receiver" ^ 5.0 / 12.0! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 14:36'! initialize "initialize the state of the receiver" super initialize. self makeVertices: self defaultSides starRatio: self defaultStarRatio withCenter: self defaultCenter withPoint: self defaultFirstVertex. self computeBounds! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/9/2005 20:15'! insureCompatability "The old stars had the point on the second not the first vertex. So we need to check for this special case." | c v1 v2 | c := vertices average rounded. v1 := vertices first . v2 := vertices second . (c dist: v1) + 0.001 < (c dist: v2) ifTrue: [vertices := vertices allButFirst copyWith: v1] ! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 12/30/2004 02:57'! makeVertices: nSides "Assuming vertices has at least one point, make a new star or regular polygon (for odd sided polygons). The center of the polygon and the first vertex remain in place. The inner distances for stars remain the same also if possible." | center r1 rN rNext a1 rTotal | center := vertices average rounded. r1 := center dist: vertices first. rN := center dist: vertices last. rNext := 1 max: r1. a1 := 270.0 + (center bearingToPoint: vertices first). rTotal := nSides even ifTrue: [rNext + rNext min: rNext + rN] ifFalse: [rNext + rNext]. rNext := rTotal - rNext. self changed . vertices := (a1 to: a1 + 359.999 by: 360.0 / nSides) collect: [:angle | center + (Point r: (rNext := rTotal - rNext) degrees: angle)]. self computeBounds. self changed! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/4/2005 19:31'! makeVertices: nSides starRatio: fraction "Assuming vertices has at least one point, make a new star or regular polygon (for odd sided polygons). The center of the polygon and the first vertex remain in place. The inner distances for stars remain the same also if possible." | center r1 rN rNext a1 rTotal | center := vertices average rounded. r1 := center dist: vertices first. rNext := 1 max: r1. rN := (1.0 min: fraction) * rNext. a1 := 270.0 + (center bearingToPoint: vertices first). rTotal := nSides even ifTrue: [rNext + rNext min: rNext + rN] ifFalse: [rNext + rNext]. rNext := rTotal - rNext. self changed . vertices := (a1 to: a1 + 359.999 by: 360.0 / nSides) collect: [:angle | center + (Point r: (rNext := rTotal - rNext) degrees: angle)]. self computeBounds. self changed! ! !StarMorph methodsFor: 'initialization' stamp: 'wiz 1/11/2005 21:36'! makeVertices: nSides starRatio: fraction withCenter: center withPoint: aPoint "Make a new star or regular polygon (for odd sided polygons). This makes star vertices from scratch without any feedback from existing vertices." | r1 rN rNext a1 rTotal | r1 := center dist: aPoint. rNext := 1 max: r1. rN := (1.0 min: fraction) * rNext. a1 := 270.0 + (center bearingToPoint: aPoint). rTotal := nSides even ifTrue: [rNext + rNext min: rNext + rN] ifFalse: [rNext + rNext]. rNext := rTotal - rNext. self changed. vertices := (a1 to: a1 + 359.999 by: 360.0 / nSides) collect: [:angle | center + (Point r: (rNext := rTotal - rNext) degrees: angle)]. self computeBounds. self changed! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 12/12/2004 16:43'! lessVertices "Reduce the number of points by one until we are a diamond. If odd reduce the number of sides by two until we become a triangle. See class comment." | nVerts | ( nVerts := 2 negated + vertices size) < 3 ifFalse: [ self makeVertices: nVerts]! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 12/11/2004 16:45'! moreVertices self makeVertices: 2+ vertices size! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:41'! nextFatter self makeVertices: vertices size starRatio: self nextSkip . self computeBounds.! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:41'! nextThinner self makeVertices: vertices size starRatio: self prevSkip . self computeBounds.! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:37'! nextTwinkle self makeVertices: vertices size starRatio: self nextTwinkleSkip . self computeBounds.! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 12/12/2004 16:40'! oneLessVertex "Reduce the number of sides by one until we are a triange. Stars will become regular polygons if the number of sides is odd. See class comment." | nVerts | ( nVerts := 1 negated + vertices size) < 3 ifFalse: [ self makeVertices: nVerts] ! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 12/11/2004 16:46'! oneMoreVertex self makeVertices: 1 + vertices size! ! !StarMorph methodsFor: 'menus' stamp: 'wiz 1/11/2005 20:37'! prevTwinkle self makeVertices: vertices size starRatio: self prevTwinkleSkip . self computeBounds.! ! !StarMorph methodsFor: 'menu' stamp: 'wiz 1/11/2005 20:27'! addChangeSidesMenuItems: aCustomMenu hand: aHandMorph "Menu items to change number of sides." aCustomMenu addLine. aCustomMenu add: 'more sides' translated action: #moreVertices. aCustomMenu add: 'fewer sides' translated action: #lessVertices. " aCustomMenu add: 'one more side' translated action: #oneMoreVertex. aCustomMenu add: 'one fewer side' translated action: #oneLessVertex"! ! !StarMorph methodsFor: 'menu' stamp: 'wiz 1/11/2005 14:55'! addCustomMenuItems: aCustomMenu hand: aHandMorph super addCustomMenuItems: aCustomMenu hand: aHandMorph. self addChangeSidesMenuItems: aCustomMenu hand: aHandMorph. self addTwinkleMenuItems: aCustomMenu hand: aHandMorph. ! ! !StarMorph methodsFor: 'menu' stamp: 'wiz 1/11/2005 20:38'! addTwinkleMenuItems: aCustomMenu hand: aHandMorph "Menu items to change the sharpness of the star." aCustomMenu addLine. aCustomMenu add: 'twinkle fatter' translated action: #nextTwinkle. aCustomMenu add: 'twinkle thinner' translated action: #prevTwinkle. " aCustomMenu add: 'fatter star' translated action: #nextFatter. aCustomMenu add: 'thinner star' translated action: #prevThinner" ! ! !StarMorph reorganize! ('editing' addHandles addStarHandles changeVertices:event:fromHandle: dragVertex:event:fromHandle: updateHandles withCenterOuterHandles withUpDownLeftRightHandlesAround:center:) ('accessing' starRatio:) ('geometry' nextSkip nextTwinkleSkip prevSkip prevTwinkleSkip) ('access' skipRatios starRatio) ('initialization' defaultBorderColor defaultBorderWidth defaultCenter defaultColor defaultFirstVertex defaultSides defaultStarRatio initialize insureCompatability makeVertices: makeVertices:starRatio: makeVertices:starRatio:withCenter:withPoint:) ('parts bin' initializeToStandAlone) ('menus' lessVertices moreVertices nextFatter nextThinner nextTwinkle oneLessVertex oneMoreVertex prevTwinkle) ('menu' addChangeSidesMenuItems:hand: addCustomMenuItems:hand: addTwinkleMenuItems:hand:) !