'From Squeak3.6 of ''6 October 2003'' [latest update: #5429] on 24 March 2007 at 9:51:28 pm'! "Change Set: earthSwarms Date: 19 February 2007 Author: Bruce O'Neel Please make sure you load the B3DTutorialFix change set as well. Thanks to Boris Gaertner (Boris.Gaertner@gmx.net) for his Ballon 3D tutorial. You use this with: EarthSwarms main. There are three classes. SRTM30Data is a mostly general GTOPO30 data reader. Note the bugs in the class comment. EarthSwarms in the main class which calls on EarthSwarmsPresenterMorph to display things. EarthSwarms has too many places where the three terrain datasets are hard coded. A more general solution, but, not until after 1 April. SRTM30Data is slightly hard coded for my system. The reading routines have hard coded path names. "! Object subclass: #EarthSwarms instanceVariableNames: 'scene terrain dataSet dataSetNum ' classVariableNames: '' poolDictionaries: '' category: 'EarthSwarms'! !EarthSwarms commentStamp: 'BEO 3/16/2007 10:53' prior: 0! EarthSwarms main class. Copies from B3DDemoSurfaces. EarthSwarms main. Thanks to Boris Gaertner (Boris.Gaertner@gmx.net) for his Ballon 3D tutorial.! BorderedMorph subclass: #EarthSwarmsPresenterMorph instanceVariableNames: 'wheels frameWidth b3DSceneMorph source textAccessor terrainDisplay dataSetDisplay aButtonDataSet1 aButtonGeneva dataSource ' classVariableNames: '' poolDictionaries: '' category: 'EarthSwarms'! !EarthSwarmsPresenterMorph commentStamp: 'BEO 2/25/2007 16:52' prior: 0! This is a slightly modified copy of B3DSceneExplorerMorph and B3DTutorialScenePresenterMorph.! Object subclass: #SRTM30Data instanceVariableNames: '' classVariableNames: 'GVAData MedData SFData ' poolDictionaries: '' category: 'EarthSwarms'! !SRTM30Data commentStamp: 'BEO 3/10/2007 21:37' prior: 0! This holds the data in the image. This is just for now, but, since it's meant to be one download this minimizes the number of places that it can fubar. Everything is on the class side. We'll have three areas for now. SF Bay area 38-37N, 237-238E. Read from w140n40.Bathmetry.srtm.gz In file coords we read from 38 down to 37, and from -123 to -122. Genoa 44 to 43N, 8-9W. Read from w020n90.Bathmetry.srtm.gz. In file coords read from 44 down to 43, and from 8 to 9. Geneva area. 46 to 46.75N, 6-6.75W. Read from w020n90.Bathmetry.srtm.gz. In file coords we read from 46.75 down to 46 and from 6 to 6.75. The two problems are: - Two hard coded areas with method names to match. - The reading code has the header data for the SRTM30 data hard coded. Usage: SRTM30Data readSFData "Read the San Francisco height data" SRTM30Data readMedData "Read the Mediterranean height data" SRTM30Data medData "Return an array with the San Francisco height data" SRTM30Data sfData "Return an array with the Mediterranean height data" SRTM30Data clearAll "Clear the stored data" BUGS: I must have something slightly wrong because non-square reading doesn't work. All the data you read must be in one file.! !EarthSwarms methodsFor: 'toplevel' stamp: 'BEO 3/13/2007 21:04'! datasetNumber: inNum dataSetNum := inNum. ! ! !EarthSwarms methodsFor: 'toplevel' stamp: 'BEO 3/23/2007 21:15'! main self datasetNumber: 0. self setTerrain: (SRTM30Data gvaData). self setDataset: SRTM30Data gvaAIRS. self show. ^self ! ! !EarthSwarms methodsFor: 'toplevel' stamp: 'BEO 3/13/2007 21:09'! main: inTerrain self setTerrain: inTerrain. self show. ^self! ! !EarthSwarms methodsFor: 'toplevel' stamp: 'BEO 3/16/2007 15:56'! show " EarthSwarms new show" | view | self createScene. (view := EarthSwarmsPresenterMorph new) source: self description: #descriptionScene; scene: scene. view rotateX: 12.0. view clearColor: (Color gray: 0.5). view parent: self. view addFrameAndExplanationField openInWorldExtent: Display extent x//2 @ (Display extent y * 7 // 8).! ! !EarthSwarms methodsFor: 'GUI Interface' stamp: 'BEO 3/13/2007 21:17'! switchDataset: flag view: view self datasetNumber: flag. (flag = 1) ifTrue: [self setDataset: SRTM30Data gvaAIRS. ]. (flag = 3) ifTrue: [self setDataset: SRTM30Data goaAIRS. ]. (flag = 2) ifTrue: [self setDataset: SRTM30Data sfoAIRS. ]. self createScene. view scene: scene.! ! !EarthSwarms methodsFor: 'GUI Interface' stamp: 'BEO 3/24/2007 12:13'! switchTerrain: flag view: view (flag = 1) ifTrue: [self setTerrain: SRTM30Data gvaData. self setDataset: SRTM30Data gvaAIRS.]. (flag = 2) ifTrue: [self setTerrain: SRTM30Data sfData. self setDataset: SRTM30Data sfoAIRS.]. (flag = 3) ifTrue: [self setTerrain: SRTM30Data medData. self setDataset: SRTM30Data goaAIRS.]. self createScene. view scene: scene.! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/23/2007 16:46'! dataset ^dataSet at: (self datasetNumber).! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/23/2007 16:46'! datasetNumber ^dataSetNum.! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/24/2007 12:16'! descriptionScene ^'Quick Help: The buttons across the top: Topography - Switches between just Topograpy or three different overlayed AIRS data sets, Surface Temperature, Water Vapor, and Cloud Fraction. There are 4 years displayed from east to west, 2003-2006, and 12 months per year displayed North to South, January-December. The colors are false colors. The button labeled Geneva, when clicked, switches between Geneva, San Francisco, and the area around Genoa Italy. Dragging the mouse in the window will move the image around.'! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/23/2007 16:59'! setDataset: inDataset "Too much is hard coded here" "We assume that we get an array of 3 items, each item is a 48 value array. This is organized as 4 years by 12 items." dataSet := Array new: 3. dataSet at: 1 put: (self makeColorField: (inDataset at: 1)). dataSet at: 2 put: (self makeColorField: (inDataset at: 2)). dataSet at: 3 put: (self makeColorField: (inDataset at: 3)). ! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/13/2007 21:02'! setDatasetNumber: inNum dataSetNum := inNum.! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/2/2007 19:33'! setTerrain: inTerrain terrain := inTerrain.! ! !EarthSwarms methodsFor: 'settingGetting' stamp: 'BEO 3/23/2007 16:45'! terrain ^terrain.! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/16/2007 15:40'! createLightsForScene: aScene | light | light :=B3DAmbientLight new. light lightColor: (B3DMaterialColor color: (Color white)). aScene lights add: light.! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/1/2007 17:43'! createScene | camera | camera _ B3DCamera new. camera position: 0@0@1000. camera target: 0@0@0. camera fov: 5.0. scene _ B3DScene new. scene defaultCamera: camera. self createSolidsForScene: scene; createLightsForScene: scene.! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/24/2007 08:28'! createSolidsForScene: aScene | sceneObj mat | sceneObj _ B3DSceneObject named: 'EarthSwarms Scene'. sceneObj geometry: (self createTrianglesFromArray: terrain). mat := B3DMaterial new. mat shininess: 0.9; emission: (Color gray: 0.22); specularPart: (Color gray: 0.1). sceneObj material: mat. aScene objects add: sceneObj. ! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/24/2007 12:20'! createTrianglesFromArray: twoDarray | colorBlock topographyColors surfaceTempColors h2oVaporColors cloudFracColors | topographyColors _ [:x :y :f | f < 0 ifTrue: [(Color h: 190 - (120 * f) s: 0.6 - (f * 0.25) v: 0.8) asB3DColor] ifFalse: [(Color h: 180 - (180 * f sqrt) s: 0.85 + (0.1 * f) v: 0.2 + (0.7 * f)) asB3DColor]]. surfaceTempColors _ [:x :y :f | (Color h: 240 - (240 * ((dataSet at: dataSetNum) at: x + 1 at: y + 1)) s: 0.6 v: 0.8) asB3DColor]. h2oVaporColors _ [:x :y :f | (Color h: 180 + (60 * ((dataSet at: dataSetNum) at: x + 1 at: y + 1)) s: 0.6 v: 0.8) asB3DColor]. cloudFracColors _ [:x :y :f | (Color h: 60 s: 1 - ((dataSet at: dataSetNum) at: x + 1 at: y + 1) v: 0.8) asB3DColor]. dataSetNum = 0 ifTrue: [colorBlock _ topographyColors]. dataSetNum = 1 ifTrue: [colorBlock _ surfaceTempColors]. dataSetNum = 2 ifTrue: [colorBlock _ h2oVaporColors]. dataSetNum = 3 ifTrue: [colorBlock _ cloudFracColors]. ^ self createTrianglesFromArray: twoDarray uFrom: nil to: nil vFrom: nil to: nil colors: colorBlock! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/24/2007 11:42'! createTrianglesFromArray: twoDarray uFrom: xStart to: xStop vFrom: yStart to: yStop colors: aBlock "here we create a triangle mesh. The scene is created elsewhere." | x y low high idxF vtx face faces mesh vtxNormals nroPx nroPy lowX highX lowY highY minVal maxVal vtxColors funVal offset | lowX _ xStart. highX _ xStop. lowX ifNil: [lowX _ 2]. highX ifNil: [highX _ twoDarray width - 1]. lowY _ yStart. highY _ yStop. lowY ifNil: [lowY _ 2]. highY ifNil: [highY _ twoDarray height - 1]. nroPx _ highX - lowX + 1. nroPy _ highY - lowY + 1. minVal _ 32767. maxVal _ -32767. lowX to: highX do: [:i | lowY to: highY do: [:j | minVal > (twoDarray at: i at: j) ifTrue: [minVal _ twoDarray at: i at: j]. maxVal < (twoDarray at: i at: j) ifTrue: [maxVal _ twoDarray at: i at: j]]]. offset _ 0. minVal > 0 ifTrue: [offset _ minVal]. vtx _ WriteStream on: (B3DVector3Array new: nroPx * nroPy). vtxNormals _ WriteStream on: (B3DVector3Array new: nroPx * nroPy). aBlock notNil ifTrue: [vtxColors _ WriteStream on: (B3DColor4Array new: nroPx * nroPy)]. x _ lowX. y _ lowY. "compute the vertices" nroPx timesRepeat: [y _ lowY. nroPy timesRepeat: [vtx nextPut: (B3DVector3 x: x - lowX - (highX - lowX / 2.0) y: 50 * ((twoDarray at: x at: y) - minVal) / (maxVal - minVal) z: y - lowY - (highY - lowY / 2.0)). vtxNormals nextPut: (B3DVector3 x: (self dxArray2D: twoDarray x: x y: y) y: -1.0 z: (self dyArray2D: twoDarray x: x y: y)) safelyNormalized. aBlock notNil ifTrue: [(twoDarray at: x at: y) < 0 ifTrue: [funVal _ (twoDarray at: x at: y) / minVal negated] ifFalse: [funVal _ (twoDarray at: x at: y) - offset / (maxVal - offset)]. vtxColors nextPut: (aBlock value: x - lowX " / (highX - lowX)" value: y - lowY " / (highY - lowY)" value: funVal)]. y _ y + 1]. x _ x + 1]. faces _ B3DIndexedTriangleArray new: nroPx - 1 * (nroPy - 1) * 2. idxF _ low _ 1. 1 to: nroPx - 1 do: [:i | high _ low + nroPy. 1 to: nroPy - 1 do: [:j | face _ B3DIndexedTriangle with: low + j - 1 with: low + j with: high + j. faces at: idxF put: face. idxF _ idxF + 1. face _ B3DIndexedTriangle with: low + j - 1 with: high + j with: high + j - 1. faces at: idxF put: face. idxF _ idxF + 1]. low _ high]. mesh _ B3DIndexedTriangleMesh new. mesh vertices: vtx contents; faces: faces. mesh vertexNormals: vtxNormals contents. aBlock notNil ifTrue: [mesh vertexColors: vtxColors contents]. ^ mesh! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 2/26/2007 13:57'! dxArray2D: arr x: x y: y "Return the X derivitive of arr at x,y" | d1 d2 | d1 := (arr at: x at: y) - (arr at: (x - 1) at: y). d2 := (arr at: (x + 1) at: y) - (arr at: x at: y). ^(d2 + d1)/2.0! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 2/26/2007 13:57'! dyArray2D: arr x: x y: y "Return the Y derivitive of arr at x,y" | d1 d2 | d1 := (arr at: x at: y) - (arr at: x at: (y - 1)). d2 := (arr at: x at: (y + 1)) - (arr at: x at: y). ^(d2 + d1)/2.0! ! !EarthSwarms methodsFor: 'support routines' stamp: 'BEO 3/24/2007 11:43'! makeColorField: inData "Hard coded way too much. Takes in an array of 48 values, 4x12. Returns an array of values scaled 0 to 1 the same size as terrain" | colorArray minVal maxVal offset val width height | self. colorArray _ Array2D width: terrain width height: terrain height. offset := -1. minVal _ 99999. maxVal _ minVal negated. 1 to: inData size do: [:i | maxVal < (inData at: i) ifTrue: [maxVal _ inData at: i]. minVal > (inData at: i) ifTrue: [minVal _ inData at: i]]. 1 to: terrain width do: [:i | 1 to: terrain height do: [:j | width _ (i - 1 * 4 / terrain width) asInteger. height _ (j - 1 * 12 / terrain height) asInteger. offset _ width * 12 + height + 1. val _ (inData at: offset) - minVal / (maxVal - minVal). colorArray at: i at: j put: val].]. ^ colorArray! ! !EarthSwarms class methodsFor: 'toplevel' stamp: 'BEO 3/13/2007 21:11'! main " EarthSwarms main." ^EarthSwarms new main. ! ! !EarthSwarms class methodsFor: 'toplevel' stamp: 'BEO 3/13/2007 21:11'! main: inTerrain " EarthSwarms main." | obj | obj := EarthSwarms new. obj setTerrain: inTerrain. obj main. ! ! !EarthSwarms class methodsFor: 'cleanup' stamp: 'BEO 2/19/2007 11:51'! cleanUpProjects "Cleanup extra projects. This doesn't belong here but it's convient" Project allSubInstancesDo: [:p | (p == Project current) ifFalse: [Project deletingProject: p]. ]. ! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 3/2/2007 20:46'! addFrameAndExplanationField | topView | topView := SystemWindow labelled: 'EarthSwarms'. topView addMorph: self fullFrame: (LayoutFrame fractions: (0 @ 0 corner: 1.0 @ 0.8)). topView addMorph: (PluggableTextMorph on: self text: #contents accept: #acceptContents: readSelection: nil menu: #codePaneMenu:shifted:) frame: (0@0.8 corner: 1@1). ^topView! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 16:59'! clearColor: aColor " set the background color of the B3DSceneMorph " b3DSceneMorph color: aColor! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! closeEnabled ^true! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! codePaneMenu: aMenu shifted: shifted "Note that unless we override perform:orSendTo:, PluggableTextController will respond to all menu items in a text pane" | donorMenu | donorMenu _ shifted ifTrue: [ParagraphEditor shiftedYellowButtonMenu] ifFalse: [ParagraphEditor yellowButtonMenu]. ^ aMenu labels: donorMenu labelString lines: donorMenu lineArray selections: donorMenu selections! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! contents ^source perform: textAccessor! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! scene ^b3DSceneMorph scene! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! scene: aScene b3DSceneMorph scene: aScene.! ! !EarthSwarmsPresenterMorph methodsFor: 'accessing' stamp: 'BEO 2/25/2007 17:00'! source: anInstance description: aSymbol source := anInstance. textAccessor := aSymbol.! ! !EarthSwarmsPresenterMorph methodsFor: 'actions' stamp: 'BEO 2/25/2007 16:54'! acceptContents: xx ^true! ! !EarthSwarmsPresenterMorph methodsFor: 'actions' stamp: 'BEO 2/25/2007 16:55'! closeMorph self delete! ! !EarthSwarmsPresenterMorph methodsFor: 'actions' stamp: 'BEO 2/25/2007 16:55'! switchRotationStatus b3DSceneMorph switchRotationStatus! ! !EarthSwarmsPresenterMorph methodsFor: 'change reporting' stamp: 'BEO 2/25/2007 17:03'! layoutChanged | ctrl | super layoutChanged. b3DSceneMorph ifNil: [^self]. b3DSceneMorph extent: (self extent - ((frameWidth * 2)@(frameWidth * 2))). b3DSceneMorph position: (self bounds origin + ((frameWidth)@(frameWidth))). wheels ifNil: [^self]. wheels isEmpty ifTrue: [^self]. ctrl := wheels at: #fov ifAbsent: [nil]. ctrl ifNotNil: [ ctrl position: self bounds corner - ctrl extent - (frameWidth@((frameWidth - ctrl extent y) / 2) rounded)]. ctrl := wheels at: #dolly ifAbsent: [nil]. ctrl ifNotNil: [ ctrl position: self bounds corner - ctrl extent - ((((frameWidth - ctrl extent x) / 2) rounded)@frameWidth)]. ctrl := wheels at: #rotX ifAbsent: [nil]. ctrl ifNotNil: [ ctrl position: (self bounds origin x + (((frameWidth - ctrl extent x) / 2) rounded))@(self bounds corner y - ctrl extent y - frameWidth)]. ctrl := wheels at: #rotY ifAbsent: [nil]. ctrl ifNotNil: [ ctrl position: (self bounds origin x + frameWidth)@(self bounds corner y - ctrl extent y - (((frameWidth - ctrl extent y) / 2) rounded))]. ctrl := wheels at: #rotZ ifAbsent: [nil]. ctrl ifNotNil: [ ctrl position: self bounds origin + ((((frameWidth - ctrl extent x) / 2) rounded)@frameWidth)]. ctrl := wheels at: #accel ifAbsent:[nil]. ctrl ifNotNil:[ ctrl position: self bounds origin + (frameWidth @ ((((frameWidth - ctrl extent y) / 2) rounded)))]. ctrl := wheels at: #accel ifAbsent:[nil]. ctrl ifNotNil:[ ctrl position: self bounds origin + (frameWidth @ ((((frameWidth - ctrl extent y) / 2) rounded)))]. ! ! !EarthSwarmsPresenterMorph methodsFor: 'drawing' stamp: 'BEO 2/25/2007 17:02'! drawOn: aCanvas "Don't fill if my b3dScene does it" (b3DSceneMorph notNil and:[b3DSceneMorph color isOpaque]) ifTrue:[ (aCanvas clipRect areasOutside: b3DSceneMorph bounds) do:[:r| aCanvas clipBy: r during:[:cc| super drawOn: cc]. ]. ] ifFalse: [super drawOn: aCanvas].! ! !EarthSwarmsPresenterMorph methodsFor: 'event handling' stamp: 'BEO 2/25/2007 17:02'! handlesMouseDown: evt ^evt yellowButtonPressed ! ! !EarthSwarmsPresenterMorph methodsFor: 'event handling' stamp: 'BEO 2/25/2007 17:03'! mouseDown: evt evt yellowButtonPressed ifTrue: [ self yellowButtonMenu. ^super mouseDown: evt].! ! !EarthSwarmsPresenterMorph methodsFor: 'hardware acceleration' stamp: 'BEO 2/25/2007 17:04'! accelerationEnabled ^b3DSceneMorph ifNil:[false] ifNotNil:[b3DSceneMorph accelerationEnabled].! ! !EarthSwarmsPresenterMorph methodsFor: 'hardware acceleration' stamp: 'BEO 2/25/2007 17:04'! accelerationEnabled: aBool ^b3DSceneMorph ifNotNil:[b3DSceneMorph accelerationEnabled: aBool].! ! !EarthSwarmsPresenterMorph methodsFor: 'hardware acceleration' stamp: 'BEO 2/25/2007 17:05'! toggleAcceleration self accelerationEnabled: self accelerationEnabled not.! ! !EarthSwarmsPresenterMorph methodsFor: 'initialization' stamp: 'BEO 3/16/2007 16:41'! closeButton "No, I have 0 idea why this might be called closeButton" | outerButton aHelp | outerButton _ AlignmentMorph newRow height: 24. outerButton beTransparent. outerButton hResizing: #spaceFill; vResizing: #shrinkWrap. "outerButton addMorph: (aButton _ UpdatingThreePhaseButtonMorph checkBox). aButton target: self; actionSelector: #toggleAcceleration; arguments: #(); getSelector: #accelerationEnabled." outerButton addTransparentSpacerOfSize: (2 @ 0). outerButton addMorph: (aButtonGeneva := SimpleButtonMorph new label: 'Geneva'). aButtonGeneva setBalloonText: (aHelp := 'Select Geneva or San Francisco'). terrainDisplay := 1. aButtonGeneva target: self; actionSelector: #toggleTerrain. outerButton addTransparentSpacerOfSize: (2 @ 0). outerButton addMorph: (aButtonDataSet1 := SimpleButtonMorph new label: 'Topography'). aButtonDataSet1 setBalloonText: (aHelp := 'Choose a data set '). dataSetDisplay := 0. aButtonDataSet1 target: self; actionSelector: #toggleDS1. outerButton addTransparentSpacerOfSize: (2 @ 0). "str _ StringMorph contents: 'Accelerate' font: nil. "(StrikeFont familyName: 'NewYork' size: 12)." miniWrapper _ AlignmentMorph newRow hResizing: #shrinkWrap; vResizing: #shrinkWrap. miniWrapper beTransparent addMorphBack: str lock. outerButton addMorphBack: miniWrapper. aButton setBalloonText: (aHelp _ 'Turn on hardware acceleration if supported'). miniWrapper setBalloonText: aHelp; setProperty: #balloonTarget toValue: aButton." ^outerButton! ! !EarthSwarmsPresenterMorph methodsFor: 'menus' stamp: 'BEO 2/25/2007 17:37'! addCustomMenuItems: aCustomMenu (aCustomMenu isKindOf: MenuMorph) ifTrue: [aCustomMenu addUpdating: #rotationString action: #switchRotationStatus] ifFalse: [aCustomMenu add: 'switch rotation status' action: #switchRotationStatus]. ! ! !EarthSwarmsPresenterMorph methodsFor: 'menus' stamp: 'BEO 2/25/2007 16:56'! addCustomMenuItems: aCustomMenu hand: aHandMorph super addCustomMenuItems: aCustomMenu hand: aHandMorph. aCustomMenu addLine. self addCustomMenuItems: aCustomMenu. ! ! !EarthSwarmsPresenterMorph methodsFor: 'menus' stamp: 'BEO 2/25/2007 16:56'! initialize | ctrl | super initialize. color := Color gray: 0.8. frameWidth := 25. b3DSceneMorph := AdvancedB3DScenePresenterMorph new. b3DSceneMorph color: Color white; borderStyle: (BorderStyle width: 1 color: Color black). self addMorphFront: b3DSceneMorph. wheels := Dictionary new. ctrl := WheelMorph new. ctrl target: b3DSceneMorph. ctrl actionSelector: #addFovAngle:. ctrl factor: -0.07. ctrl setBalloonText: 'FOV'. self addMorphFront: ctrl. wheels at: #fov put: ctrl. ctrl := WheelMorph new. ctrl target: b3DSceneMorph. ctrl actionSelector: #addDolly:. ctrl factor: 0.005. ctrl beVertical. ctrl setBalloonText: 'Dolly'. self addMorphFront: ctrl. wheels at: #dolly put: ctrl. ctrl := WheelMorph new. ctrl target: b3DSceneMorph. ctrl actionSelector: #rotateZ:. ctrl beVertical. ctrl setBalloonText: 'z Axis'. self addMorphFront: ctrl. wheels at: #rotZ put: ctrl. ctrl := WheelMorph new. ctrl target: b3DSceneMorph. ctrl actionSelector: #rotateY:. ctrl setBalloonText: 'y Axis'. self addMorphFront: ctrl. wheels at: #rotY put: ctrl. ctrl := WheelMorph new. ctrl target: b3DSceneMorph. ctrl actionSelector: #rotateX:. ctrl beVertical. ctrl setBalloonText: 'x Axis'. self addMorphFront: ctrl. wheels at: #rotX put: ctrl. ctrl _ self closeButton. self addMorphFront: ctrl. wheels at: #accel put: ctrl. ! ! !EarthSwarmsPresenterMorph methodsFor: 'menus' stamp: 'BEO 2/25/2007 16:57'! rotationString ^b3DSceneMorph isRotating ifTrue: ['stop rotating'] ifFalse: ['start rotating']! ! !EarthSwarmsPresenterMorph methodsFor: 'menus' stamp: 'BEO 2/25/2007 16:57'! yellowButtonMenu | menu sel | menu _ CustomMenu new. menu title: self class name. self addCustomMenuItems: menu. sel := menu startUp. sel ifNotNil: [self perform: sel]! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:57'! addDolly: a b3DSceneMorph addDolly: a! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:57'! beRotating b3DSceneMorph beRotating! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:58'! defaultColor ^Color gray! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:58'! panBy: a b3DSceneMorph panBy: a! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:58'! rotateX: a b3DSceneMorph rotateX: a! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:58'! rotateY: a b3DSceneMorph rotateY: a! ! !EarthSwarmsPresenterMorph methodsFor: 'visual properties' stamp: 'BEO 2/25/2007 16:58'! rotateZ: a b3DSceneMorph rotateZ: a! ! !EarthSwarmsPresenterMorph methodsFor: 'Earth Swarms Interface ' stamp: 'BEO 3/3/2007 20:46'! parent: parent dataSource := parent.! ! !EarthSwarmsPresenterMorph methodsFor: 'Earth Swarms Interface ' stamp: 'BEO 3/16/2007 11:13'! toggleDS1 "Swaps between DS1 and DS2 displays" dataSetDisplay := dataSetDisplay + 1. (dataSetDisplay > 3) ifTrue: [dataSetDisplay := 0.]. (dataSetDisplay = 0) ifTrue: [aButtonDataSet1 label: 'Topography'.]. (dataSetDisplay = 1) ifTrue: [aButtonDataSet1 label: 'AIRS Surface Temp'.]. (dataSetDisplay = 2) ifTrue: [aButtonDataSet1 label: 'AIRS H2O Vapor'.]. (dataSetDisplay = 3) ifTrue: [aButtonDataSet1 label: 'AIRS Cloud Frac'.]. dataSource switchDataset: dataSetDisplay view: self. ! ! !EarthSwarmsPresenterMorph methodsFor: 'Earth Swarms Interface ' stamp: 'BEO 3/4/2007 14:57'! toggleTerrain "Swaps between different Terrains" terrainDisplay := terrainDisplay + 1. (terrainDisplay > 3) ifTrue: [terrainDisplay := 1.]. (terrainDisplay = 1) ifTrue: [aButtonGeneva label: 'Geneva'.]. (terrainDisplay = 2) ifTrue: [aButtonGeneva label: 'San Francisco'.]. (terrainDisplay = 3) ifTrue: [aButtonGeneva label: 'Genoa'.]. dataSource switchTerrain: terrainDisplay view: self. ! ! !EarthSwarmsPresenterMorph class methodsFor: 'initialization' stamp: 'BEO 2/25/2007 16:53'! descriptionForPartsBin ^ self partName: 'EarthSwarms' categories: #('3-D') documentation: '3D Earth Data Display'! ! !SRTM30Data methodsFor: 'see class side' stamp: 'BEO 3/3/2007 20:54'! seeClassSide "See the class side"! ! !SRTM30Data class methodsFor: 'initialization' stamp: 'BEO 3/2/2007 19:31'! clearAll "Clear all the data" SRTM30Data clearMed. SRTM30Data clearSF. SRTM30Data clearGVA. ! ! !SRTM30Data class methodsFor: 'initialization' stamp: 'BEO 3/2/2007 19:31'! clearGVA "Clear the GVA data" GVAData := nil.! ! !SRTM30Data class methodsFor: 'initialization' stamp: 'BEO 2/27/2007 19:53'! clearMed "Clear the Mediterranean data" MedData := nil.! ! !SRTM30Data class methodsFor: 'initialization' stamp: 'BEO 2/27/2007 19:53'! clearSF "Clear the SF data" SFData := nil.! ! !SRTM30Data class methodsFor: 'reading data' stamp: 'BEO 3/3/2007 20:32'! readData: fn fileStartLon: fileStartLon fileStartLat: fileStartLat startLon: startLon startLat: startLat lonLen: lonLen latLen: latLen "Read in the data. Pixel size, nrow, ncols, bytesize, and byte order are all hard coded to match GTOPO30 files Reads from fn which has a starting Longitude of fileStartLon and a starting latitude of fileStartLat. Reads starting at startLon and startLat for lonLen and latLen. NOTE: Everything is in DEGREES. Array values are in meters" | ncols nrows pixelSize nullValue values width height startRow startCol startByte bytesPerValue skipBytes inFile word | ncols := 4800. nrows := 6000. bytesPerValue := 2. pixelSize := 0.00833333333333. nullValue := -9999. width := (1 + (latLen / pixelSize)) asInteger. height := (1 + (lonLen / pixelSize)) asInteger. (width > ncols) ifTrue: [self error: 'width of array is greater than ncols']. (height > nrows) ifTrue: [self error: 'height of array is greater than nrows']. values := Array2D width: width height: height. startRow := ((fileStartLat - startLat) / pixelSize) abs asInteger. startCol := ((fileStartLon - startLon) / pixelSize) abs asInteger. startByte := bytesPerValue * ((startRow * ncols) + startCol). (startByte > (bytesPerValue * ncols * nrows)) ifTrue: [self error: 'starting beyond the end of file']. skipBytes := bytesPerValue * (ncols - width). (skipBytes < 0) ifTrue: [self error: 'reading more than ncols worth of data']. inFile := StandardFileStream readOnlyFileNamed: fn. inFile position: startByte. 1 to: width do: [:i | 1 to: height do: [:j | word := ((inFile next asInteger) << 8 + (inFile next asInteger)). (word > 32767 ) ifTrue: [ word := ((word - 1) bitXor: 16rFFFF) negated ]. values at: (height - j + 1) at: i put: word ]. inFile position: (skipBytes + (inFile position)). ]. inFile close. ^values.! ! !SRTM30Data class methodsFor: 'reading data' stamp: 'BEO 3/3/2007 20:35'! readGVAData "Read in the Mediterranean data" GVAData := SRTM30Data readData: '/home/edoneel/earthSwarmsData/srtm30_plus/w020n90.Bathmetry.srtm' fileStartLon: -19.99583 fileStartLat: 89.99583 startLon: 6 startLat: 46.75 lonLen: 0.75 latLen: 0.75. ! ! !SRTM30Data class methodsFor: 'reading data' stamp: 'BEO 3/3/2007 21:02'! readMedData "Read in the Mediterranean data" MedData := SRTM30Data readData: '/home/edoneel/earthSwarmsData/srtm30_plus/w020n90.Bathmetry.srtm' fileStartLon: -19.99583 fileStartLat: 89.99583 startLon: 8 startLat: 44.5 lonLen: 1.0 latLen: 1.0. ! ! !SRTM30Data class methodsFor: 'reading data' stamp: 'BEO 3/2/2007 19:49'! readSFData "Read in the SF data" SFData := SRTM30Data readData: '/home/edoneel/earthSwarmsData/srtm30_plus/w140n40.Bathmetry.srtm' fileStartLon: -139.995833 fileStartLat: 39.99583 startLon: -123 startLat: 38 lonLen: 1 latLen: 1. ! ! !SRTM30Data class methodsFor: 'reading data' stamp: 'BEO 3/2/2007 18:53'! readValaisData "Read in the Mediterranean data" MedData := SRTM30Data readData: '/home/edoneel/earthSwarmsData/srtm30_plus/w020n90.Bathmetry.srtm' fileStartLon: -19.99583 fileStartLat: 89.99583 startLon: 7 startLat: 44.5 lonLen: 1.0 latLen: 1.0. ! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 3/13/2007 20:49'! goaAIRS "Returns the GOA AIRS data as a 3 (for 3 datasets) by 48 (approx) months worth of data" "The data starts in 2003 and runs through 2006, and, is SurfAirTemp_A (in Kelvin), TotH20Vap_A (in mm), and CloudFrc_A" ^#( #("Surface Tempreture" 270.414 269.859 275.0 "inserted value" 280.352 287.633 293.289 291.0 "inserted value" 289.0 "inserted value" 288.422 280.352 279.641 273.711 270.695 274.297 274.648 280.328 286.328 289.492 291.070 291.516 288.766 284.680 276.227 273.695 271.469 269.484 275.172 281.164 287.523 292.578 291.398 290.336 288.766 285.578 277.0 "inserted value" 270.906 271.141 271.875 273.430 279.664 286.336 290.156 293.539 288.438 291.688 286.742 280.039 275.719) #( "TotH20Vap_A " 4.55908 3.40479 5.0 "inserted value" 6.46143 11.1709 17.5254 15.0 "inserted value" 12.5 "inserted value" 9.93066 6.83301 7.89258 5.05225 4.90430 4.39453 5.17725 8.27246 9.20898 12.2217 15.9082 17.5469 12.2412 11.1650 6.16406 4.69434 3.63940 4.03857 6.23730 7.33252 10.9307 14.6641 15.1250 13.8564 14.0029 9.08203 6.5 "inserted value" 4.26709 3.74438 4.38965 5.16357 7.37988 11.2090 13.2520 17.6699 11.2998 14.8828 10.9121 6.79590 4.77344) #("CloudFrc_A" 0.517578 0.313965 0.31 "inserted value" 0.320801 0.476074 0.271240 0.26 "inserted value" 0.25 "inserted value" 0.249756 0.339355 0.436523 0.362305 0.572754 0.312500 0.450684 0.462891 0.388428 0.417725 0.424561 0.442871 0.261719 0.487061 0.380859 0.391602 0.366211 0.360352 0.305420 0.477295 0.280029 0.301270 0.462646 0.384277 0.379883 0.290039 0.40 "inserted value" 0.497559 0.397461 0.415039 0.466553 0.391357 0.516602 0.315430 0.298096 0.438721 0.311523 0.361572 0.416748 0.309082 ))! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 3/13/2007 20:54'! gvaAIRS "Returns the GVA AIRS data as a 3 (for 3 datasets) by 48 (approx) months worth of data" "The data starts in 2003 and runs through 2006, and, is SurfAirTemp_A (in Kelvin), TotH20Vap_A (in mm), and CloudFrc_A" ^#( #(277.477 "Surface Tempreture" 277.555 283.0 "inserted value" 288.086 293.031 298.938 297.0 "inserted value" 295.0 "inserted value" 293.250 286.945 283.789 279.344 278.062 281.594 284.508 287.117 291.242 295.820 297.789 296.031 294.570 292.172 284.047 280.133 277.727 277.195 283.875 288.195 292.969 297.156 297.594 295.328 293.039 289.969 282.0 "inserted value" 276.789 278.320 279.039 282.719 288.562 293.227 296.570 299.672 294.367 296.648 291.977 286.234 281.594) #(7.77441 "TotH20Vap_A " 6.31689 8.8 "inserted value" 11.3633 16.3887 23.4219 20.0 "inserted value" 17.0 "inserted value" 15.1377 12.8535 12.6084 8.91016 8.05371 7.63721 8.34277 11.8330 14.1758 18.4258 21.0430 22.2461 18.7168 18.6934 10.6865 8.83594 6.25781 6.04932 8.62207 12.0869 14.4854 20.2344 21.7266 20.1914 19.6133 15.7725 11.7 "inserted value" 7.22998 6.42627 7.29004 10.0508 11.9736 16.4082 18.9883 25.3242 17.2051 22.2227 15.8623 12.3164 8.56836) #("CloudFrc_A" 0.376953 0.291260 0.30 "inserted value" 0.312988 0.323486 0.194336 0.196 "inserted value" 0.198 "inserted value" 0.202637 0.374512 0.503906 0.362549 0.402100 0.375732 0.279785 0.487061 0.359863 0.233276 0.168579 0.281982 0.152344 0.409424 0.318359 0.257812 0.219360 0.322266 0.239746 0.322998 0.358643 0.193848 0.179199 0.264404 0.295410 0.323975 0.35 "inserted value" 0.373291 0.280273 0.312500 0.436035 0.297607 0.361816 0.224365 0.208008 0.254639 0.265137 0.242798 0.263184 0.262451))! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 3/2/2007 19:32'! gvaData "Return the data for GVA" ^GVAData! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 2/27/2007 20:00'! medData "Return the data for the Mediterranean" ^MedData.! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 2/27/2007 20:00'! sfData "Return the data for San Francisco" ^SFData! ! !SRTM30Data class methodsFor: 'fetch data' stamp: 'BEO 3/13/2007 20:42'! sfoAIRS "Returns the SFO AIRS data as a 3 (for 3 datasets) by 48 (approx) months worth of data" "The data starts in 2003 and runs through 2006, and, is SurfAirTemp_A (in Kelvin), TotH20Vap_A (in mm), and CloudFrc_A" ^#( #("Surface Tempreture" 272.859 272.773 280.0 "default value" 281.734 285.875 291.023 280.0 "default value" 280.0 "default value" 288.656 285.797 270.258 271.047 269.516 275.297 277.461 285.867 287.680 292.812 292.945 295.547 285.844 281.984 275.164 269.367 268.320 275.141 278.898 286.773 290.047 288.969 290.227 292.203 286.180 281.344 282.0 "default value" 271.883 273.961 270.336 275.688 283.656 289.500 291.781 293.961 292.406 292.133 283.492 271.625 272.492 ) #( "TotH20Vap_A " 7.15771 6.34326 9.0 "average value" 8.95312 10.1641 14.5127 9.0 "average value" 9.0 "average value" 13.6855 11.9277 4.55518 6.06543 5.28613 6.89355 7.42627 9.36914 10.6572 14.7363 16.9355 18.1680 11.7949 9.81934 7.71094 6.56445 5.31250 6.20898 7.70703 8.12012 11.8145 15.0781 15.5312 14.7715 11.4648 8.99316 10.0 "average value" 5.68408 6.10254 4.97803 5.63818 8.18555 11.5957 13.2529 17.1035 13.8887 14.3623 9.26953 5.35742 7.03125 ) #("CloudFrc_A" 0.453125 0.475342 0.47 "default value" 0.523438 0.508789 0.467285 0.47 "default value" 0.47 "default value" 0.291016 0.395020 0.561035 0.571289 0.602051 0.457275 0.441650 0.339600 0.506836 0.254150 0.317627 0.303711 0.440674 0.414062 0.575684 0.617676 0.518066 0.272705 0.317627 0.325684 0.370605 0.596680 0.551758 0.315674 0.457520 0.476807 0.530762 0.499268 0.410156 0.438721 0.406494 0.487793 0.388916 0.425293 0.337402 0.350342 0.291016 0.551270 0.47 "default value" 0.545898 ))! ! !SRTM30Data class reorganize! ('initialization' clearAll clearGVA clearMed clearSF) ('reading data' readData:fileStartLon:fileStartLat:startLon:startLat:lonLen:latLen: readGVAData readMedData readSFData readValaisData) ('fetch data' goaAIRS gvaAIRS gvaData medData sfData sfoAIRS) ! !SRTM30Data reorganize! ('see class side' seeClassSide) ! !EarthSwarmsPresenterMorph class reorganize! ('initialization' descriptionForPartsBin) ! EarthSwarmsPresenterMorph removeSelector: #ds1Displayed! EarthSwarmsPresenterMorph removeSelector: #ds2Displayed! EarthSwarmsPresenterMorph removeSelector: #gvaDisplayed! EarthSwarmsPresenterMorph removeSelector: #openInSystemWindow! EarthSwarmsPresenterMorph removeSelector: #sfoDisplayed! EarthSwarmsPresenterMorph removeSelector: #toggleDS2! EarthSwarmsPresenterMorph removeSelector: #toggleGVA! EarthSwarmsPresenterMorph removeSelector: #toggleSFO! !EarthSwarmsPresenterMorph reorganize! ('accessing' addFrameAndExplanationField clearColor: closeEnabled codePaneMenu:shifted: contents scene scene: source:description:) ('actions' acceptContents: closeMorph switchRotationStatus) ('change reporting' layoutChanged) ('drawing' drawOn:) ('event handling' handlesMouseDown: mouseDown:) ('hardware acceleration' accelerationEnabled accelerationEnabled: toggleAcceleration) ('initialization' closeButton) ('menus' addCustomMenuItems: addCustomMenuItems:hand: initialize rotationString yellowButtonMenu) ('visual properties' addDolly: beRotating defaultColor panBy: rotateX: rotateY: rotateZ:) ('Earth Swarms Interface ' parent: toggleDS1 toggleTerrain) ! !EarthSwarms class reorganize! ('toplevel' main main:) ('cleanup' cleanUpProjects) ! EarthSwarms removeSelector: #createGeometry:uFrom:to:vFrom:to:divisionU:divisionV:coloring:! EarthSwarms removeSelector: #createLightsForScene8:! EarthSwarms removeSelector: #createSolidsForScene8:! EarthSwarms removeSelector: #createSolidsForSceneSave:! EarthSwarms removeSelector: #createTriangleGeometry:withDerivatives:and:uFrom:to:vFrom:to:divisionU:divisionV:coloring:! EarthSwarms removeSelector: #createTriangleGeometryAndTexture:! EarthSwarms removeSelector: #createTrianglesFromArray:uFrom:to:vFrom:to:! EarthSwarms removeSelector: #oldCreateLightsForScene:! !EarthSwarms reorganize! ('toplevel' datasetNumber: main main: show) ('GUI Interface' switchDataset:view: switchTerrain:view:) ('settingGetting' dataset datasetNumber descriptionScene setDataset: setDatasetNumber: setTerrain: terrain) ('support routines' createLightsForScene: createScene createSolidsForScene: createTrianglesFromArray: createTrianglesFromArray:uFrom:to:vFrom:to:colors: dxArray2D:x:y: dyArray2D:x:y: makeColorField:) !