links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
How to set a morph's heading
Last updated at 5:51 pm UTC on 31 October 2006
On January 04, 2004 Jack Johnson asked: “I was messing around with EToys and grabbed an arrow morph and a couple of ellipses and wanted to have the arrow morph automatically place itself between the two ellipses and point from one to the other. The placement was easy, but I had trouble computing the heading. I did come across a formula used for computing a bearing based on two map coordinates:
 tc1=mod(atan2(sin(lon1-lon2) * cos(lat2),cos(lat1) *
     sin(lat2)- sin(lat1) * cos(lat2)* cos(lon1-lon2)),2 * pi)
which would work just fine, but being relatively new to Squeak I'm at a loss for how to implement it, or how to even find out if/how Squeak implements the atan2 function. Any pointers or suggestions?
Jack got a number of answers. Listed separately below.

From: Bert Freudenberg Sent: Sunday, January 04, 2004 8:27 AM
Doing math with EToys is not as easy as we wish sometimes ... but Squeak provides almost everything you'll ever need. The method you are looking for probably is Point>>bearingToPoint:. It's just a bit odd how to get that into your EToy. Here is one way:
	Arrow's heading - Yellow's heading + Red's heading “This is only to get references to both ellipses into the script.”
		self setHeading: Yellow1 getHeading + Red1 getHeading
		self setHeading: (Yellow1 costume center bearingToPoint: Red1 costume center)
It uses the ellipses' costumes directly because they provide the #center method - EToy itself does not support Points, only Numbers like x and y.
(From: Frank Shearar Sent: Monday, January 05, 2004 8:10 AM Shouldn't #bearingToPoint: use #radiansToDegrees instead of a constant?
In other words,
    ^ ((deltaX >= 0 ifTrue: [90] ifFalse: [270])
            - ((deltaY / deltaX) arcTan negated radiansToDegrees)) rounded
(From: Jack Johnson Sent: Monday, January 05, 2004 12:31 AM I did find that after editing the text of the script (to insert/juggle parentheses) that toggling back to the tile version undid my textual changes. I assumed it was because the changes I had made could not be adequately represented by the tiles.)

From: David T. Lewis Sent: Sunday, January 04, 2004 12:35 PM
Bert gave you a good answer for the problem you are trying to solve, but as a newcomer to Squeak you may also be interested in knowing "how do I write this math formula in Squeak?". To answer that, I'm going to drop down a level into the Smalltalk language that is working underneath the EToys envinroment.

If you were trying to write a C function to solve your problem, you would poke through the manuals and translate your formula into a function that might look more or less like this:
     double get_tc1(double lat1, double lon1, double lat2, double lon2)
      return fmod(atan2(sin(lon1-lon2) * cos(lat2), cos(lat1) *
             sin(lat2)-sin(lat1) * cos(lat2) * cos(lon1-lon2)), 2 * M_PI);
In Squeak, you would toss out the manuals (well, there aren't any manuals to toss out, but you don't need them anyway). Go the "Tools" flap on the right side of the screen, and pull out a Workspace and a Method Finder (which opens up a "Selector Browser", don't ask me why). You can use the Selector Browser to find the math functions you need, and you can build up your formula piece by piece in the Workspace, testing it as you go.

In the upper left pane of the Selector Browser, try entering "cos" and seeing what you come up with. You will see the arcCos method right away, and the cos method a little further down the list. After you experiment a little with this, you will see that the methods that you are looking for tend to live in the classes called Number and Float, so you can open browsers on these classes and find all of the normal arithmetic and math functions that you would expect.

A couple of things are a bit tricky though. In the C program, you needed to use the fmod() function, which is specifically designed to work with double precision floating point data types. If you wanted to use a modulo function for integers, you would have to use the % operator instead of fmod(), and if you were using other kinds of numbers, you might need to use the fmodf() function or the fmodl() function. In Squeak Smalltalk, the numbers are all smart enough to figure out how to interact with one another, so once you look through the arithmetic operators and find "\\" representing the modulo function, you can just use it on any kind of number (including Float, which is a double precision floating point under the covers).

The other tricky thing is that instead of using the C macro M_PI to represent the constant value for pi, you can look for "pi" in the Selector Browser, and find out that there is a "class side method" that shows up as "Float class pi". This is where Squeak remembers the constant value of pi, and you can refer to it by evaluating the expression "Float pi".

One more small oddity: In this example, I will use ":=" as the assignment operator. When you are doing this in Squeak, you can use the underscore character "_" for assignment instead of ":=". It will show up as a nice left-arrow in Squeak, and it means exactly the same thing as ":=". You will find that most of the code in Squeak uses the left arrow (underscore) instead of ":=", but since it would look funny in this email message, I used ":=" for the example.

That's all you need to know to start building up your formula. If you go to your Workspace and enter some numbers and expressions to play around with, you might end up with something like this:
	—- evaluate the following in your workspace —-
	lat1 _ 203.
	lon1 _ 113.
	lat2 _ 479.
	lon2 _ 501.
	tc1 := (((lon1 - lon2) sin &star lat2 cos)
	         arcTan: ((lat1 cos &star lat2 sin) - (lat1 sin &star lat2 cos &star (lon1 - lon2) cos)))
	           \\ (2 &star Float pi)
	—- end of workspace stuff —-
This produces the same result as the C program (through the first 13 significant digits, which is all you get out of double precision anyway). The values that assigned to lat1, lon1, lat2, and lon2 are just number that I made up, you can experiment with any values you want.

Of course, you can turn the Smalltalk expression into a method that you can call from other objects. This makes it equivalent to the function call in C. And it is also very interesting to try evaluating your expression in the debugger, which you can do by adding the expression "self halt." in your workspace right before the "tcl := ... " stuff. Now when you evaluate the code in your workspace, a debugger will open. Experiment with this, and you will find that you can step through the formula evaluation and see exactly how the various number objects are interacting with one another and how the math functions work.

But at this point, you should probably go back to Bert's answer, which will head you back in the direction you really wanted to go.

From: Colin Putney Sent: Sunday, January 04, 2004 12:54 PM
Just in case you're more interested in the diagram than the math, I'd also suggest having a look at Ned Konz' Connectors package. It's very good at dealing with ellipses connected by arrows. You can install Connectors via SqueakMap

From: How to save a part bin Sent: Sunday, January 04, 2004 1:37 PM
Well, the math has been described. However, there's another strategy, and that's to use my Connectors package.

In Connectors, I had to do two things to do what you describe (say if you make a Connector and tell both of its ends to "attach to nearest point to center").

	intersectionWithLineSegmentFromCenterTo: aPoint 
		| dx aSquared bSquared m mSquared xSquared x y dy |
		(self containsPoint: aPoint)
			ifTrue: [ ^aPoint ].
		dx _ aPoint x - self center x.
		dy _ aPoint y - self center y.
		dx = 0
			ifTrue: [ ^self bounds pointNearestTo: aPoint ].
		m _ dy / dx.
		mSquared _ m squared.
		aSquared _ (self bounds width / 2) squared.
		bSquared _ (self bounds height / 2) squared.
		xSquared _ 1 / ((1 / aSquared) + (mSquared / bSquared)).
		x _ xSquared sqrt.
		dx  0 ifTrue: [ x _ x negated ].
		y _ m  x.
		^ self center + (x @ y) asIntegerPoint.

From:Andreas Raab Sent: Sunday, January 04, 2004 5:41 PM
    Angle's x - Destination's x - Source's x.
    Angle's y - Source's y - Destination's y.
    Arrow's heading - Angle's theta + 90.