Look Ma, no hands

I had a great clock face. Now it was a simple matter to add the hands and make them go around. Not.

I had drawn a minute hand from a diamond shape object and stretched it out so that it had a nice appearance. The code for rotation is similar to the code I used to position the ticks around the clock face. The code located the Left and Top in the sheet window using Sin and Cos of the angle in radians (0 to 2 pi). With each re-postioning, I rotated the MinuteHand object to a new orientation in degrees.

By the way, the help implies that there is a Pi() function that will return the value of pi. In Excel. Not in VBA. So I created my own pif() function to take its place. Similarly, Min() and Max() are available as spreadsheet functions but not as native functions. Someday I will get around to changing them to “Application.WorksheetFunction.Pi()”, “Application.WorksheetFunction.Min()” and “Application.WorksheetFunction.Max()”.

The result of all of this was that the Minute hand went around the face and changed angle for about 12 ticks and then jumped to what seemed to be an arbitrary location and continued from there for about another 1/4 turn when it jumped again. This odd behavior continued around until it got back to where it started.

After messing with it and trying to figure out what it was doing by stepping through it, I created another program to learn about how the shape was behaving. I put some code in to fill in the spreadsheet with the values for the tick number, Top, Left, Angle, Degrees and such. What I learned was that the bounding box for the shape:

1. Does not always contain the shape or conversely does not always closely adhere to the bounds of the the object.

2. The bounding box jumps from one orientation (portrait) to another (landscape) suddenly at a predictable but poorly documented rotation of the enclosed object.

3. The shape rotates around the center of the bounding box.

I drew this out on the white board and looked at it a long time.  With the various points and triangles came the solution.

The pivot-point of the hand was the mid-point of the end of the drawn figure.  The pointer-end was at the opposite side.  The shape-center was the midpoint of the diagonal between (Left, Top) and (Left+Width, Top+Height).  From the shape-center, find where the hand-pivot-point is now, after rotation.  Find the delta between that place and the clock-face Center (I used the center of the window).  Add those delta-x and delta-y to the current bounding box Left and Top.  Then the hand shape will be properly positioned and oriented.  Rotate, determine delta, shift. Repeat.

The code in the following post needs to be placed after the code in the previous post.  And until I figure out how to make WordPress leave the code format alone, it will be lacking indentation.  Sorry.

Starting Time

In order to understand the drawing model In Excel, I first went to the book that I have, John Walkenbach’s Microsoft Excel 2000 Power Programming With VBA.  This is an excellent, well-written source of good information about using Excel whether you want to program or not.  It is well organized, helps you avoid problems and pretty much leads you through many aspects of creating good spreadsheets and VBA.  John Walkenbach has some other books on Excel including a more up-to-date version of this one.

Excel 2000 PP w/VBA was light on shapes. There are some examples on the CD. The only real references that I found helpful for what I needed on shapes were the programming introductory section regarding Cell Comments and how the Excel Object Model hierarchy may or may not have the property that you think that you want to change.  Do not skip the section on Comments if you really want to understand VBA for Excel (and probably Word, Powerpoint and Access).

Another important source of information is the help system in Excel Visual Basic for Applications.  This is easy to use in the VBA Integrated Development Environment (IDE), providing help with parameters, properties, applies to, and methods. For most help, just put the cursor on the word you want help with and press the F1 key.  The examples are usually trivial and it is sometime hard to find good examples that come close to what you want to do.

The third source of information is Create Macro.  Curious about code? Select Tools==>Macro==>Record New Macro and do something with the things you are interested in.  In my case, I created some shapes, moved them around, rotated them, gave them colors, etc.  Take notes as you do this though. Select Tools==>Macro==>Stop Recording.  Then Tools==>Macro==>Macros. Select the macro you just recorded (Macro 1?) and Click Edit.  Review and take note of the things that you want to do and the properties you need to be interested in.

Making a clock face was straight forward.  Ticks, text boxes, text.  Size based on window size.  About half an hour and that was done.

Now just add the hands.

About an hour into drawing the minute hand or rather making it move around, I separated the minute hand into its own spreadsheet.  I added code to log the values of the angles (radians and degrees are requred), and the x’s and y’s used in calculation.  Once I could see the changes in the values, the things required for the next baby step became apparent.

More in the next post.

Shapes Object

I had been thinking about a little programming project for Microsoft Excel.  In order to complete the project, I needed to have a better understanding of the drawing engine.  I proposed for myself a little recreation to get a better understanding of what that would entail.

My idea was to make an analog clock, the kind with hands that go around.  Simple shape rotation stepped by a counter.  Not quite so.

The shapes in Microsoft Excel are located by their Top and Left properties.  No problem.  Just locate and rotate the hands as required.  Not so fast.  The shape rotates around its center.  No problem a bit harder to locate the Top and Left, but wait…there’s more.

It seems that the bounding box, the imaginary box that would enclose a shape does not track the rotating object.  Yes that’s right, the bounding box may or may not enclose the rotating shape.  And this.  The place where it changes is not an obvious thing that you could program to.  How to rotate the hand around the center of the clock as if it were a pivot.

An excellent suggestion I got was “why not put the center of the hand-shape in the center of the clock and hide the other part.  Good idea but it just moves the problem to the other side.  Since I have not learned yet how to color just half of a shape, I would have to have a second shape that matched the background that would act as a cover-up.  But I would have to rotate it just has I had the original.
In the end, i found a way to do it what I needed so it will be the subject of the next few blogs.

Microsoft Software

I spent a perfectly frustrating day trying produce results with Microsoft software. I normally use Excel and although it is not as good as it was around V4 or V5 and does support more rows than it did back then it cannot hold a really large number of rows (more than 65000). So I thought I could put my data into an Access database…silly me. If I thought that Microsoft Excel was clueless about dates and more importantly times, I had not reckoned with Access. Access, what a piece of junk. I spent all afternoon trying to get the mainframe to format the data in a way that Access would read it in without success. I even got it to recognize that the dates were dates and the times were times but when it read it in, #NUM error. And of course there is no log, no message, no nothing. Junk. And absolutely no help to resolve the problem. Another reason to not use Microsoft products. If they were available without charge, they would be overpriced.

A Spell for Halloween

For Halloween I thought that I would re-publish this:

Candidate for a Pullet Surprise:
An Owed to A Swell Checker

I have a spelling checker —
It came with my PC
It plane lee marks four my revue
Miss steaks aye can knot sea

Eye ran this poem threw it,
Your sure reel glad two no.
Its vary polished in it’s weigh–
My checker tolled me sew.

A checker is a bless sing.
It freeze yew lodes of thyme.
It helps me awl stiles two reed,
And aides me when aye rime.

To rite with care is quite a feet
Of witch won should be proud.
And wee mussed dew the best wee can,
Sew flaws are knot aloud.

And now bee cause my spelling
Is checked with such grate flare,
There are know faults with in my cite;
Of non eye am a wear.

Each frays come posed up on my screen
Eye Trussed to be a joule.
The checker poured over every word
To cheque sum spelling rule.

That’s why aye brake in two averse
By righting wants too pleas.
Sow now ewe sea why aye dew prays
Such soft wear for pea seas!

Credited to Jerry Zar, Dean of the Graduate School,
Northwestern Illinois University

Progress?

I found this in a file save 10 years ago.

If Oracle made toasters…

They’d claim their toaster was compatible with all brands and styles of
bread, but when you got it home you’d discover the Bagel Engine was still
in development, the Croissant Extension was three years away, and that
indeed the whole appliance was just blowing smoke.

If Hewlett-Packard made toasters…

They would market the Reverse Toaster, which takes in toast and gives you
regular bread.

If IBM made toasters…

They would want one big toaster where people bring bread to be submitted
for overnight toasting. IBM would claim a worldwide market for five, maybe
six toasters.

If Xerox made toasters…

You could toast one-sided or double-sided. Successive slices would get
lighter and lighter. The toaster would jam your bread for you.

If Radio Shack made toasters…

The staff would sell you a toaster, but not know anything about it. Or you
could buy all the parts to build your own toaster.

If Thinking Machines made toasters…

You would be able to toast 64,000 pieces of bread at the same time.

If Cray made toasters…

They would cost $16 million but would be faster than any other
single-slice toaster in the world.

If The Rand Corporation made toasters…

It would be a large, perfectly smooth and seamless black cube. Every
morning there would be a piece of toast on top of it. Their service
department would have an unlisted phone number, and the blueprints for the
box would be highly classified government documents. The X-Files would have
an episode about it.

If the NSA made toasters…

Your toaster would have a secret trap door that only the NSA could access
in case they needed to get at your toast for reasons of national security.

If Sony made toasters…

The ToastMan, which would be barely larger than the single piece of bread
it is meant to toast, can be conveniently attached to your belt.

If Timex made toasters…

They would be cheap and small quartz-crystal wrist toasters that take a
licking and keep on toasting.

If Fisher Price made toasters…

“Baby’s First Toaster” would have a hand-crank that you turn to toast the
bread that pops up like a Jack-in-the-box.

If Microsoft made toasters…

Every time you bought a loaf of bread, you would have to buy a toaster. You
wouldn’t have to take the toaster, but you’d still have to pay for it
anyway. Toaster’95 wouldweigh 15000 pounds (requiring a reinforced steel
countertop), draw enough electricity to power a small city, take up 95% of
the space in your kitchen, would claim to be the first toaster that lets
you control how light or dark you want your toast to be, and would secretly
interrogate your other appliances to find out who made them. Everyone would
hate Microsoft toasters, but nonetheless would buy them since most of the
good bread only works with their toasters.

If Apple made toasters…

It would do everything the Microsoft toaster does, but 5 years earlier.

Michael Masley

One of the CD’s that I just took off the player is by Michael Masley. I think that I bought this one near the corner of Jefferson and Hyde in San Francisco in 1999 when I was there for a SHARE conference. I guess that Michael Masley is still going strong as attested by his own web site and the number of Google entries. But most especially by the Wikipedia article. A very intense, dedicated, talented and interesting fellow. He played on the street outside Mac Expo in January.

Eclipse

Finally got around to looking at Eclipse as an IDE for Java. I had tried it about a year ago with much aggravation over heap size. Trying it with Ubuntu 7.4 did not work because Eclipse said that the pointer to Java did not have a valid executable. I have been using Sun

Java  version "1.5.0_11"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
Java HotSpot(TM) Client VM (build 1.5.0_11-b03, mixed mode, sharing)

and the SDK at the same level.

With Ubuntu, the trick is to get Eclipse to look at the right version of Java. The key to the trick is update-java-alternatives. For more detail on update-java-alternatives, do the man page (man update-java-alternatives):

myid@mypc:~/Projects/eclipse$ man update-java-alternatives
Reformatting update-java-alternatives(8), please wait...

The basic idea is to first list the java versions available on your system:

update-java-alternatives -l

Then to pick one and bring the Ubuntu world into alignment with the desired Java world. The way to do this is:

update-java-alternatives -v -s your-desired-java

from the list just displayed. Omit the -v if you hate gory details.

It goes something like this:

my-id@my-pc:~/Projects/eclipse$ update-java-alternatives -l
java-1.5.0-sun 53 /usr/lib/jvm/java-1.5.0-sun
java-gcj 1041 /usr/lib/jvm/java-gcj
my-id@my-pc:~/Projects/eclipse$ update-java-alternatives -v -s java-1.5.0-sun
update-java-alternatives: no root privileges
my-id@my-pc:~/Projects/eclipse$ sudo update-java-alternatives -v -s java-1.5.0-sun
Password:
resetting java alternatives
Using `/usr/lib/jvm/java-1.5.0-sun/bin/appletviewer' to provide `appletviewer'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/apt' to provide `apt'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/extcheck' to provide `extcheck'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/HtmlConverter' to provide `HtmlConverter'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/idlj' to provide `idlj'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jarsigner' to provide `jarsigner'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jar' to provide `jar'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/javac' to provide `javac'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/javadoc' to provide `javadoc'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/javah' to provide `javah'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/javap' to provide `javap'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/java-rmi.cgi' to provide `java-rmi.cgi'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jconsole' to provide `jconsole'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jdb' to provide `jdb'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jinfo' to provide `jinfo'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jmap' to provide `jmap'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jps' to provide `jps'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jsadebugd' to provide `jsadebugd'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jstack' to provide `jstack'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jstatd' to provide `jstatd'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/jstat' to provide `jstat'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/native2ascii' to provide `native2ascii'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/rmic' to provide `rmic'.
Using `/usr/lib/jvm/java-1.5.0-sun/bin/serialver' to provide `serialver'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/ControlPanel' to provide `ControlPanel'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/java' to provide `java'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/java_vm' to provide `java_vm'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/javaws' to provide `javaws'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/keytool' to provide `keytool'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/orbd' to provide `orbd'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/pack200' to provide `pack200'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/policytool' to provide `policytool'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/rmid' to provide `rmid'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/rmiregistry' to provide `rmiregistry'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/servertool' to provide `servertool'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/tnameserv' to provide `tnameserv'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/bin/unpack200' to provide `unpack200'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/plugin/i386/ns7/libjavaplugin_oji.so' to provide `firefox-javaplugin.so'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/plugin/i386/ns7/libjavaplugin_oji.so' to provide `iceape-javaplugin.so'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/plugin/i386/ns7/libjavaplugin_oji.so' to provide `iceweasel-javaplugin.so'.
Using `/usr/lib/jvm/java-1.5.0-sun/jre/plugin/i386/ns7/libjavaplugin_oji.so' to provide `mozilla-javaplugin.so'.
my-id@my-pc:~/Projects/eclipse$

And even though the Eclipse pages say that Eclipse does not look at JAVA_HOME it does seem to care:

my-id@my-pc:~/Projects/eclipse$ eclipse
using specified vm: /usr/java/j2sdk1.4.2
my-id@my-pc:~/Projects/eclipse$ update-java-alternatives -l
java-1.5.0-sun 53 /usr/lib/jvm/java-1.5.0-sun
java-gcj 1041 /usr/lib/jvm/java-gcj
my-id@my-pc:~/Projects/eclipse$ export JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun
my-id@my-pc:~/Projects/eclipse$ eclipse
using specified vm: /usr/lib/jvm/java-1.5.0-sun
Could not create /usr/local/lib/eclipse/.eclipseextension. Please run as root:
touch /usr/local/lib/eclipse/.eclipseextension
chmod 2775 /usr/local/lib/eclipse/.eclipseextension
chown root:staff /usr/local/lib/eclipse/.eclipseextension

Did I mention that your first run of Eclipse should be as a root id so that it can create /usr/local/lib/eclipse/.eclipseextension

my-id@my-pc:~/Projects/eclipse$ sudo eclipse
Password:
using specified vm: /usr/lib/jvm/java-1.5.0-sun
cbcalvin@natalie:~/Projects/eclipse$ eclipse
using specified vm: /usr/lib/jvm/java-1.5.0-sun
Mar 15, 2008 5:20:27 PM org.apache.catalina.startup.Embedded start
INFO: Starting tomcat server
Mar 15, 2008 5:20:27 PM org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/5.5
Mar 15, 2008 5:20:27 PM org.apache.catalina.core.StandardHost start
INFO: XML validation disabled
Mar 15, 2008 5:20:28 PM org.apache.catalina.loader.WebappLoader start
INFO: Dual registration of jndi stream handler: factory already defined
Mar 15, 2008 5:20:28 PM org.apache.catalina.loader.WebappLoader setClassPath
INFO: Unknown loader org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@1087be0 class org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader
Mar 15, 2008 5:20:29 PM org.apache.coyote.http11.Http11BaseProtocol init
INFO: Initializing Coyote HTTP/1.1 on http-127.0.0.1-49371
Mar 15, 2008 5:20:29 PM org.apache.coyote.http11.Http11BaseProtocol start
INFO: Starting Coyote HTTP/1.1 on http-127.0.0.1-49371
cbcalvin@natalie:~/Projects/eclipse$ eclipse
using specified vm: /usr/lib/jvm/java-1.5.0-sun

After doing these things, Eclipse seems to work fine if a bit sluggish from a lack of memory. I will probably provide some more on this topic later.