Program Windbarb // KPL version 2 // This program is a demonstration of user interaction with // wind barbs to input wind speed and direction from mouse // interactions. The "RealVector class" is enhanced for // the displays. The arrow shape of the vector has been // replaced with a traditional wind barb. The head and tail // are entered with a mouse and displayed with barbs. // // From the 1956 school text "Weather Analysis and Forecasting" // 2nd edition by Sverre Pettersen, Ph.D. // // "The wind direction and speed are indicated by an arrow // the shaft of which indicates the direction toward which // the wind is blowing, And the barbs indicate the number // of knots .... A short barb indicates 5 knots, // a long barb 10 knots, And a filled triangle 50 knots." // copyright (c) 2006 by Jim Halbach Method Main() Define V As RealVector // The vector defined by the user Define Head As Point // The head and tail of the Define Tail As Point // user's vector Define Head_1 As Point // rev 1 Define GotTail As Boolean // True if user clicks a point Define GotHead As Boolean // True if user clicks another point Define W As Decimal // Dimensions of the screen Define H As Decimal Define i As Integer // A loop counter // Set up the screen. Maximize ( ) W = ScreenWidth ( ) H = ScreenHeight ( ) // Show one vector after another until the user quits. While True PenWidth ( 3 ) // Ask user to define a vector. JumpTo ( 0, 0 ) PrintLine ( "Select a station, click two points to make a vector." ) // Watch for the user to define a vector V. // Then display vector V. as line with barbs. While True // Watch for the user to click on two points. If MouseEvent = "ButtonDown" Then If Not GotTail Then Tail =( CreatePoint ( MouseX, MouseY )) GotTail = True ElseIf Not GotHead Then Head = ( CreatePoint ( MouseX, MouseY )) GotHead = True While MouseEvent = "ButtonDown" Delay ( 1 ) End While End If While MouseEvent = "ButtonDown" Delay ( 1 ) End While End If // If the user has already clicked on two points, create // the vector V. If GotHead And GotTail Then // Erase the instructions. ClearBackground ( White ) // Create V, the user's vector. V.CreateFromPoint ( CreatePoint ( Head.X - Tail.X, Head.Y - Tail.Y )) // Find number of windbarbs V.barbsize( V.Length ) // rev 1 If V.sizebarb = True Then printline ( converttostring(V.numbarb*10+5) + " knots" ) // rev 1 Else printline ( converttostring(V.numbarb*10) + " knots" ) // rev 1 End If // Show V at the first point the user clicked. V.Position = Tail Color ( Blue ) V.Drawbarb () // rev 1 Break End If RefreshScreen ( ) End While // Wait for the user to click somewhere (to continue). JumpTo ( 0, 0 ) ContinueToNext ( ) // After the user clicks, clear the screen // and go around again. ClearBackground ( White ) GotHead = False GotTail = False End While End Method Class RealVector // This class defines a vector space over the real numbers. // Each vector is defined by a direction and a length. // The standard representation of the vector is with its // tail at the point (0, 0) and its head at a point // determined by the vector's direction and length. The // representation may be moved by changing the value of // Position (the location of the tail). // Jamey Friend, May 4, 2006 // The standard representation of a vector has been changed // so that the head and tail meanings are reversed. This // implies that point (0, 0) is a pivot point. The length // of the line is fixed with barbs attached to the clockwise // side of the line. Full barbs for each 10 knots, one half // barb for 5 knots, and triangles for each 50 knots. // Jim Halbach, September 14, 2006 Define Direction As Decimal Define Length As Decimal Define Position As Point Define numbarb As Integer // rev 1 Define sizebarb As Boolean // rev 1 Define lastbarb As Integer // rev 1 Method barbsize( length As Decimal ) // rev 1 // sizebarb is true for 5 miles, false for 10 miles // numbarb is the number of barbs, last may be 5 mile. sizebarb = True length = length*10 numbarb = length / 10 lastbarb = round(length - ( numbarb * 10 )) If lastbarb > 5 Then sizebarb = False numbarb = numbarb + 1 End If numbarb = numbarb / 10 End Method Method Drawbarb ( ) // Draws a wind barb vector. with barbs instead of length Define VX As RealVector Define i As Integer If numbarb <> 0 Then DrawLine ( Barbs (numbarb*10+30 ).X, Barbs ( numbarb*10+30 ).Y, Position.X, Position.Y ) For i = numbarb To 1 Step -1 VX.Create ( Direction, 30 ) VX.Negate ( ) VX.Position = Barbs ( i*10+30 ) VX.Rotate ( -135 ) DrawLine ( VX.Head ( ).X, VX.Head ( ).Y, VX.Position.X, VX.Position.Y ) Next If sizebarb Then VX.Create ( Direction, 20 ) Else VX.Create ( Direction, 00 ) End If VX.Negate ( ) VX.Position = Barbs ( 30 ) VX.Rotate ( -135 ) DrawLine ( VX.Head ( ).X, VX.Head ( ).Y, VX.Position.X, VX.Position.Y ) End If End Method Method Negate ( ) // Negates a vector, i.e., changes its direction by 180 degrees. Direction = CanonicalAngle ( Direction + 180 ) End Method Method Rotate ( A As Decimal ) // Rotates this vector by the angle A. Direction = CanonicalAngle ( Direction + A ) End Method Method Create ( D As Decimal, L As Decimal ) // Creates a vector with a direction D and a length L If L < 0 Then L = Abs ( L ) D = CanonicalAngle ( D + 180 ) End If Direction = CanonicalAngle ( D ) Length = L Position = CreatePoint ( 0, 0 ) End Method Function CreateRealVector ( D As Decimal, L As Decimal ) As RealVector // Returns a new RealVector with direction D and length L Define V As RealVector If L < 0 Then L = Abs ( L ) D = D + 180 End If V.Direction = CanonicalAngle (D) V.Length = L V.Position = CreatePoint ( 0, 0 ) Return V End Function Method CreateFromPoint ( P As Point ) // Creates a vector with the tail at (0, 0) and the // head at the point P. Me.Head ( ) = P If P.x = 0 Then If P.y >= 0 Then Direction = 90 Else Direction = 270 End If Else Direction = CanonicalAngle ( RadiansToDegrees ( ArcTan ( P.y/P.x ))) If P.X < 0 Then Direction = CanonicalAngle ( Direction - 180 ) End If End If Length = Sqrt ( P.X*P.X + P.Y*P.Y ) Position = CreatePoint ( 0, 0 ) End Method Function Clone ( ) As RealVector // Returns a copy of this vector. Return CreateRealVector ( Direction, Length ) End Function Function CanonicalAngle ( A As Decimal ) As Decimal // Reduces an angle in degrees to its canonical form, i.e., // to a value from 0 up to (but not including) 360. While A < 0 A = A + 360 End While While A >= 360 A = A - 360 End While Return A End Function Method JumpTo ( x As Integer , y As Integer ) // This is a trick to move invisibly to the point (x, y). DrawLine ( x, y, x, y ) End Method Function Barbs ( size As Integer ) As Point // Determines where the head of this vector is. Return CreatePoint ( size*cos ( DegreesToRadians ( Direction )) + Position.X, size*Sin ( DegreesToRadians ( Direction ))+ Position.Y) End Function Function Head ( ) As Point // Determines where the head of this vector is. Return CreatePoint ( Length*cos ( DegreesToRadians ( Direction )) + Position.X, Length*Sin ( DegreesToRadians ( Direction ))+ Position.Y) End Function End Class Method JumpTo ( x As Integer , y As Integer ) // This is a trick to move invisibly to the point (x, y). DrawLine ( x, y, x, y ) End Method Method JumpToPoint ( P As Point ) // This is a trick to move invisibly to the point P. DrawLine ( P.X, P.Y, P.X, P.Y ) End Method Method ContinueToNext ( ) // Ask the user to click to continue. Wait for the click. Print ( "Select a station location and click:" ) While Not MouseEvent = "ButtonDown" Delay ( 1 ) End While While MouseEvent = "ButtonDown" Delay ( 1 ) End While End Method End Program