Thursday, November 24, 2011

Backup and Synchronize Contacts

This morning, I was taking a look at my system for backing up my files. Everything seems pretty much under control except for my contacts. It seems that I have many different contact systems and they are all completely independent. Here is a list:

  • Windows Contacts: (Start -> All Programs -> Windows Contacts) These appear to be completely obsolete, but I don’t dare to delete them. Actually, I probably will.
  • Windows Live Contacts on my desktop system.
  • Windows Live Contacts on my laptop system.
  • Contacts in Thunderbird.
  • Contacts in G Mail.
  • My on-line address book.

Remember that mostly, I just want to back up the contact list, but it would also be nice if there could be some sort of synchronization between some of them.

To make matters worse, Microsoft tends to hide all the contact information deep within directory structures that it also makes inaccessible. What a pain.

So, I did an internet search and what I found was that I was supposed to add Windows Live Messenger to tie all this stuff together. Just what I need: another database, but at least this one is in the cloud and would synchronize between my desktop and laptop systems. Not perfect, but it meets my minimum requirements.

 

Windows Live Messenger

Well, I am still not sure exactly what Microsoft Live Messenger actually is, but I think it is Microsoft’s answer to Facebook. Whatever it is, I would just as soon not have it on my systems, but I am willing if it will do the job. The websites extolling its virtues promised to synchronize with Windows Live Mail contacts, so I decided to give it a try. I downloaded and installed it. This may not actually have been necessary, but I did it.

And it did not synchronize with Windows Live Mail. I thought that the problem could be that I had different account names for Windows Live, so I created a new Windows Live account using the email account from at which I read my email messages. That made no difference.

Eventually, I think I found the trick.

  • Open Windows Live Mail.
  • Click Contacts in the lower left of the window.
  • That changes the ribbon bar at the top of the window.
  • At the right side of the ribbon, there is an icon. On my system, it offered me the option to Sign In. I did using my Windows Live ID. I think this was the key to synchronizing.
  • At this point, the icon changed to show my name and a drop down list which allows log out, change user and similar things.
  • I also clicked Clean Up Contacts. I don’t know if this was necessary, but it was probably a good idea.
  • I then went to my laptop, opened Windows Live Mail and logged into that program as well. I clicked Clean Up Contacts and the contacts appeared there. I had not installed Windows Live Messenger on that system.

I also note that with Contacts selected in Windows Live Mail, there are options on the ribbon to import or export my contact list. While I have not yet thought of a way to make this automatic, it would offer me a means of saving my contacts to a file that could be backed up.

So, I guess this solves my problem. It is not perfect, but it does seem to meet my immediate concerns.

Monday, October 10, 2011

Creating a WPF Web Application

I had a LOT of trouble getting anything working. This will help avoid future pitfalls.
I started by opening a new application:
Visual C# –> Windows –> WPF Browser Application.
Next, I tried to add a WPF Window. WRONG! I should have added a WPF Page. They are very similar, but a WPF Window would not work. I named the page Trans_Main.xaml.
At this point, the project was set up to run Page1.xaml. To change this, I went into the App.xaml file and corrected the StartupUri parameter.
This worked on IE, but when I tried to run it on Chrome, it reported that I was missing a Plug In.
I also noted that the Debug tab in the Project Properties window lets us select the Start Action. I had hoped that I could set this to Trans_Main.xaml, but this did not work. I had to set it to …bin\Debug\Translate.xbap. In fact, double clicking this file would bring up the Trans_Main.xaml file, but double-clicking the Trans_Main.xaml file directly caused an error.
I tried eliminating x:Class="Translate.Trans_Main"  from the XAML file. After that, IE would open and display the file.  I put the line back and copied the EXE file to the bin directory and this seemed to work. I tried setting the program to build directly to the bin directory (instead of bin\debug), but this seemed to mess things up. I did not play with it for long enough to figure out why.
Bottom line is that this technology is OK for use with Internet Explorer, but not for other browsers. I guess I will stick to using WPF for Applications only.
(Note to self: See the project in c:\wwwroot\inetpub\Translate)

Tuesday, September 27, 2011

How to build Help into a WPF Program

Over the last couple of days, I have spend an inordinate amount of time trying to figure out how to integrate on-line help into my WPF programs. I am amazed at how difficult it was to find concise and useful information on this subject. In fact, it makes me think that I must be missing something major. Also, it seems that none of my programming books do a very good job covering the subject.

In fact, creating the Help File and Linking to it are two separate topics and will be dealt with separately.

Lest there be any doubt, we are limiting ourselves to creating “CHM” help files.

Using HTML Help Workshop

This is a free download from Microsoft and it is pretty basic. It starts with HTML files into which you can put links to other HTML files. You add these HTML files to a Table of Contents as “Topics”. You can also insert Headings and Files. My theory is that a Heading is just like a Topic, except that it does not NEED to have an HTML file associated with it.

The biggest draw-back to this program is that it does not allow interactive editing of HTML files. Also, it was far from intuitive to use. I found an excellent Help Workstation Tutorial by Char James-Tanny. I downloaded it from http://frogleg.mvps.org/helptechnologies/htmlhelp/hhtutorials.html.

BUT – there is something better out there for preparation of CHM files.

Using HelpNDoc to create Help Files

A search for Free Help Authoring Tools brought me to http://www.helpndoc.com/ from whence I was able to download HelpNDoc which is free for non-commercial use.

This program is very cool and I think it could be just the thing I need for documenting programs. The reason that it would be better than MS Word or something like that is that it allows me to work in outlines and it allows me to enter hyperlinks. It would be really nice if allowed me to follow them while I was authoring something, but you can’t have everything.

It comes with a pretty good on-Line help system of its own and is pretty easy to use.

Another nice thing about it is that it outputs in any or all of four different formats: CHM, HTML, DPF and Word.

And if you look in the CHM folder, it seems that it puts out all the files that would be used by HTML Help Workshop. According to one source, HTML Help Workshop must be installed for HelpNDoc to compile its help projects.

It was not clear that it allows you to create indexes, but if this is important, one might be able to do this using HTML Help Workshop as a post-processing step. Experimentation would be useful here.

Linking to help from WPF Programs

As nice as these free programs are, neither explains how to link a WPF application to the help.

The Char James-Tanny tutorial does discuss linking using the hhctrl.ocx control from VB 5/6 and perhaps it would be possible to adapt those instructions.

Apparently, there is a System.Windows.Forms.HelpProvider control. This appears to not work with WPF controls.

I did, however, find a way to open CHM help files.

But first, a little about the structure of HelpNDoc.

HelpNDoc builds a help system out of Topics. Each Topic is one entry in the table of contents, and when as the help system is being built, it creates an HTML file on the topic. This HTML file gets compressed and included in the CHM file, but a copy of the HTML file is left in the CHM directory.

This topic gets a name or Help ID based on the Topic Name in the Table of Contents. You can change this Help ID by right clicking the TOC entry. This Help ID plus “.html” is used as the name of the HTML file for this topic.

You can also add Anchor points to a Topic. You can set an anchor by placing the cursor where you want the anchor, going to the Insert tab and clicking Insert/Remove Anchor on the right side of the ribbon. The program then prompts you to enter the name of the anchor. You can see a green bar where the anchor is placed, but unfortunately, I did not find a way to go back later and see what the name had been set to. I was able to see it after generating the help file by looking at the source code in the resulting HTML file.

So, now we have a generated CHM help file, HTML files holding topics that have been compiled into this help file and possibly anchors in some of the Topic/ HTML files. How do we access them.

The answer is to use the static ShowHelp method of System.Windows.Forms.Help. Here is what the calls will look like. Assume that the help file is named MyHelp.chm. Assume that the Help ID is MyTopic and that the topic file in that help file is therefore named MyTopic.html. Also, there is an anchor point in this file named MyAnchor. You might want to use a full path instead of just a filename.

To open the help file at the beginning, use:

Help.ShowHelp(null, @"MyHelp.chm");

The following will open the help file at the MyTopic page:

Help.ShowHelp(null, @" MyHelp.chm", "MyTopic.html");

And the following will open the help file at the anchor point:

Help.ShowHelp(null, @"MyHelp.chm", "MyTopic.html#MyAnchor");

So, that is enough to get me started. As I learn more, perhaps I will update this note.

Friday, September 23, 2011

Using my LG Dare as a Music Server

I like to listen to music while I am in my workshop. You would think this would be easy, and it would be if I were not so lazy. I want to be able to walk into the shop, throw a switch, and just have the music start – without thinking about a thing.

You might think that a radio would be just the thing, but there is only one passable FM radio station in my area and while I like a lot of their music, I don’t love it.

What about an old computer? Well, I don’t want to keep it on all the time or wait for it to boot up or log on or anything like that.

And how about Satellite Radio? Well, I am too cheap to pay for it.

But the LG Dare, plugged into a small charger, running all the time, might be just right. I plan to put the speakers onto the switch that I turn on when I enter the shop, so they will draw power only when I am using them.

Loading the Music

One can certainly use V-Cast/Rhapsody to load music. In fact, I had to install the V-Cast software on one of my computers in order to figure out the file structure of the Dare. But my goal is to pop micro-SD cards into and out of the Dare as my music store. I figure that it will be easier than using special software.

So, I loaded V-Cast onto the Vista side of the Timeline-X computer and told it to connect to the Dare. I then dragged some music  files from a windows explorer folder into the music directory on the Dare. I added a playlist and put a few songs into that as well.  The display on V-Cast shows that I had three folders: music, albums and playlists. I told the system to disconnect from the Dare, powered down the Dare, and removed the micro-SD card.

When I plugged the micro-SD card into my main computer, it had five folders on it:

  • media
  • my_flix
  • my_music
  • my_pix
  • my_sounds

The music was in the my_music folder (with all file names in lower case). I could not find the playlist; I searched for it several times. My only guess is that this could be on the part of the Dare that is not removable. It seems that all the music goes into this folder without subdirectories.

Thursday, September 22, 2011

Experimenting with iTunes

In my last post, I described tools I had written that would:

  • Swap names of artists when they had been rendered with a comma. Holly, Buddy became Buddy Holly, etc.
  • Update the metadata for the files based on their locations using the old structure.
  • Remove the track number from the start of the file names.
  • If the file was part of a collection, attempt to extract artist name from the file name and move it to a directory for that artist.

I ran this on the M:\ drive and it worked (even though I had to designate the M drive using \\wd-netcenter\Music rather than “M:\”.

This is all well and good, but it left me with a couple of problems:

  • iTunes put a lot of crap into the library that was NOT on the M drive. I don’t want this crap in the library.
  • I wanted to give all the tracks a default Rating of two stars. That way I can change only the ones I want to be other than “normal”.
  • Previously, there had been a lot of track in the library that did not in fact exist on the disk. I needed some way to expunge those.

I decide to try to write code to do this.

I wondered if I could do this my editing playlists. These could be in either tab-separated text or XML. I created a Playlist and added a track to it. I then exported the playlist to a text file, modified it to change the rating and then imported it again. The import worked, but it did not change the rating.

 

Working with Library.xml

I learned that I could export the entire library as an XML file (but not a text file) by using File -> Library -> Export. It was easy to spot fields for Location and Rating.

According to Francisco Balena, there are two ways to manage XML. I started with what he said would be the easier one: using an xml reader and an xml writer. I figured out how to use them, but I also soon learned that this is handling the xml at a very low level and would require a huge amount of coding.

Instead, I loaded the whole thing into an xml document and then figured out how to navigate down to the information on the individual tracks. I did this pretty much by trial and error – looking at the library.xml file as text in one window and opening nodes in Visual Studio to figure out which child of each node I wanted to use.

I did run into one interesting problem. Visual Studio would not allow me to use “M:\” as the root of my music server. Instead, I had to call it \\wd-netcenter\Music. I have no idea why.

I put a feature into Music Manager to update the library.xml file. It does two things:

  • If the Location is other than on the M drive, it removes the track from the DOM.
  • If there is no Rating, it adds a rating of “40” which corresponds to two stars, my default.

I then started iTunes while holding the shift key. This allows me to specify the XML library I want to enter. I had to key in the file names, since the file-open dialog only shows .ITL files. It took two or three hours to complete this and when it was done, it told me that the file was incompatible and offered to try to repair it. This appears to be taking even longer. I think it is trying to reload album artwork or something like that.

Well, this DID work. It took about 6 hours to grind through everything, but in the end, it appears to have worked. Still, I am not interested in waiting for 6 hours to do a small update. Plus, it appears that there are still a lot of duplicate files. I can probably find them fairly easily by scanning, but I am not looking forward to deleting them one by one.

I think the iTunes SDK will be better suited to what I want to do

 

Repairing the damage done by the XML efforts

By searching the Internet, I found numerous articles on how to link to the iTunes COM object. It looked pretty easy – except for one thing. I could not initiate the App object. It kept telling me that: The folder containing “LibraryOutcannot be found, and is required. Please choose or create a new iTunes library.

I wrestled with this for several hours. I could not find a library.itl file that iTunes seemed to be using. This was supposed to be in MyMusic\iTunes, but the one I found there did not have a late enough data on it and did not seem to change when I made changes to the library. Also, I renamed it and iTunes still seemed to start when invoked by itself. I finally gave up and went out to split some wood and think about it.

I have now decided that the problem must be that when I tried to start iTunes using the output file from my XML efforts, it changed the directory in which it was looking for the íTunesLibrary.itl file as well as the name of the file it was looking for.

Here is what I will do:

  • Change registry so that \HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellFolders\MyMusic now points to “M:\”. Also changed ..\User Shell Folders\My Music.
  • Made sure there was a directory named m:\iTunes.
  • I note that there is an iTunes Library.itl file in there and it is dated from this morning before I tried to do the import from the XML efforts. I held the shift key down while starting iTunes so that it prompted me to select the library.
  • I now note that the date on my iTunes Library.itl is set to current time.
  • I tried to run the program again and this time I got a different error.
  • I closed iTunes and tried again. This time I was prompted to specify the name of the library which I did. The program now seems to work as expected.
  • BUT – it seems that the location information is gone from most of the files. I am going to just empty the library and reload the whole thing.

Getting iTunes reloaded

Well, I got to where I wanted to – at least to step 1.

Here is what I did:

  • Cleared the entire library by selecting everything in it and clicking Delete.
  • Reloaded it by File -> Add Folder to Library.
  • That took many hours.
  • I then wrote a program to set all the Ratings to 2 stars (40). I ran it and that worked, but again took a couple of hours.
  • I went through the entire list and changed the ratings of the tracks that I liked better than 2 stars. I added some smart playlists.
  • I tried to write one of them to a CD (as an “MP3 CD”). It was going to be 200 files with 600+ MB of data. It has been grinding for a couple of hours. I don’t know if it is hung or not.

Conclusion:

iTunes seems to be pretty cool, but it is severely lacking in a couple of aspects. Here is no easy way to:

· Find and remove duplicate music.

· Copy sets of tracks (i.e. a playlist) to another directory for eventual movement to a phone.

· Move files to a different directory.

· Set the rating on a group of files at the same time.

As a result, I expect that I will write a program to assist with using iTunes. I will come up with a rough spec on this and post it.

 

 

Notes on using the iTunes SDK

While waiting around for the library to load, I did some internet searching and found that there is an SDK for iTunes. I registered as a Free apple developer (see PasswordSafe) and downloaded the SDK. Mostly, it consists of a help file. Turns out that the DLL is already installed with iTunes.

Here are some useful sites that I found:

http://www.robertprice.co.uk/robblog/archive/2006/8/iTunes_Now_Playing_In_C_.shtml

http://www.ohscope.com/2009/04/02/itunes-com-api-in-c/

http://www.codeproject.com/KB/cs/itunes_and_net.aspx

http://ratnakarg.wordpress.com/tag/c-itunes-sdk/

The following tells how to iterate over the tracks in the library and assign artwork to them. Should be easy to modify to make other modifications as well.

http://www.diller.ca/?p=40

The following tells how to add names to a playlist

http://www.itunessdk.com/blog/itunes-sdk-examples/

And this one that deletes tracks where the source is no longer available:

http://www.hanselman.com/blog/RemovingDeadTracksDuplicatesThatDontExistFromITunesUsingC.aspx

This one shows how to build a simple viewer/player based on the iTunes library.

http://www.codeproject.com/KB/audio-video/iTuneit.aspx

And this one shows how to make an audio recorder in c# based on iTunes

http://www.codeproject.com/KB/audio-video/MP3WaveAudioRecorder.aspx

Monday, September 19, 2011

Messing with my Music Collection

Today, I am messing with my music collection. The goal was to get it ready for a massive import into iTunes.

 

Previous System

In the past, I tried to organize my music by putting it into a directory with folders named for major genres. Under those were folders named for artists. Under those were albums and the recorded MP3 tracks were in those folders. For singles, I had an “album” named “Singles” or something like that.

My Jukebox program would read this information into a database and allow me to select and play recordings and groups of recordings. This worked well enough, but was not portable to portable devices.

Another problem was that much or most of my music had been recorded from vinyl. There was no metadata in those MP3 files and iTunes and other library systems depended heavily upon that information.

 

The Music Manager Program

Back in the Spring, I wrote a “Music Manager” program. This program placed information from the file structure of my programs into the metadata. This was a huge step forward.

Yesterday, I copied all my music from its original location in the “M” drive (out in the garage) to directory E:\Music for iTunes. It was still organized by album.

I had already used the Metadata Update feature of Music Manager to insert metadata into the music files based on their file names and where they were on the directory tree.

This morning, I used Music Manager to reorganize this information:

  1. If the artist name had a comma in it, I used the Artist Name Update feature (which I wrote this morning) to reverse what was before and after the comma. If there is also an ampersand in it, pause for manual intervention.

1. Rerun the Metadata Update feature to update the metadata to reflect the new artist name.

2. Added a feature to remove track number from the song titles. At the same time, I moved the tracks out of the album directories, putting them in directories directly under the artist.

3. I have not yet processed the JPG and XML files or removed the album files.

 

About Play Lists

This is what I learned about Playlists.

  • You can export them by right-clicking into a tab separated value text file.
  • I want to add a feature to Music Manager that will copy everything from an exported playlist to a particular disk or SD card location.
  • Eventually, I will move the library back to the shared drive so that all computers can access it.
  • I will need a feature to “Move” a play list so that it can be used on a computer that thinks the master directory of music is at a different location.
  • It would be good to know the relationship between a rating in the metadata(If there is one) and the rating in iTunes. Also, what happens if I import a playlist that gives a different rating to a song than how it is already rated in iTunes. What if I import a playlist with songs that are not already present in iTunes. Would this be a way that I could set ratings programmatically?

Friday, August 12, 2011

Notes on Dependency Objects

For the last several days ( yes – days! ) I have been trying to understand Dependency Objects as they relate to 3D graphics. I have been reading Ptezold’s 3D Programming for Windows as well as Applications = Code + Markup. I have also searched the internet for tutorials, the best of which was at: http://www.wpftutorial.net/DependencyProperties.html. I think the problem is that most discussions were overly complicated and perhaps not specific enough to what I was trying to do.

So here is my summary of what I learned relative to what I, myself, am trying to do right now! FYI – my current project is something that I call WoodCAD. It does a lot of 3D graphics and makes very heavy use of Dependency Objects.

 

Introduction to Dependency Objects

To a first approximation, just think of Dependency Objects as a way to define a property. They are fancy, but from the outside at least, they just look like a simple property. Once you have your head around that, understand that dependency properties also offer the following:

  • Its data is stored not in the class that holds it, but rather in some sort of mysterious dictionary that you don’t really have to understand completely in order to use. Have some faith that the data is there somewhere.
  • Dependency properties can only be used by a class that is descended from the Dependency Object class. That’s because its parent class provides a couple of methods that you need to use dependency properties
  • Dependency Properties have a default value that is used if no other value has been explicitly assigned. Note that this is one value per class that does not need to be set in the instance can use the default value.
  • You can specify a method that gets called whenever its value changes. This is the coolest thing about them and the main reason for using them here.
  • You can specify a Coerce method that is applied to the value before you try to use it. A good example would be trimming a string to fit within a particular size. This is totally optional and I am not currently using it.
  • You can specify a Validate method that tests the value and throws and error if it does not pass. The Validate method gets the new value after it has been processed by the Coerce method. Again, this is completely optional and I am not currently using it.
  • · The last thing is that if the Dependency Property you are defining is itself a Dependency Object, then the Changed Method gets triggered if you change the entire object, or if you change any dependency objects within the Dependency Object. This is what hung me up and I will give an example so that you will wonder how it was ever confusing to me. See the section named Cascading Dependency Objects.

 

Setting up a simple Dependency Object

Let’s make up a Dependency Object named Length that will be a property of our class named MyClass.

Start with the property definition – sometimes called the CLR definition:

public double Length {
set {SetValue(LengthProperty, value);}
get {return (int)GetValue(LengthProperty);}
}

See – It’s just a simple property.

Get and Set Value are methods defined by Dependency Object from which the class you are working in must be extended. Length Property is defined as follows:

public static readonly DependencyProperty LengthProperty =
DependencyProperty.Register(
"Length",
typeof(double),
typeof(MyClass),
new PropertyMetadata(new Point3DCollection(), LengthPropertyChanged)
);

It seems to come from a kind of Property Factory. But no matter. You get it by registering it. It is an object instance in its own right and you feed it to the Get and Set Value methods.

The first parameter in the Register method is a string that must be the name of the property. Next is the type to be held in the Dependency Object. After that is the type of the class that is using it. Next is Property Metadata (more on that in the next paragraph.) I could also have included an optional Validation callback here, but did not.

Now, about Property Metadata: Property Metadata allows us to specify the default value (an empty Point 3D Collection) as well as the call back method. A third parameter of Property Metadata that we did not use here is the Coerce method which is a private static that returns object and expects a sender (Dependency Object) and a value (object) as parameters.

And more about the Validate Method: Note that this is an optional parameter of the Dependency Property Register method, rather than the Property Metadata constructor. This is a private static bool that expects a single object parameter holding the proposed new value. If this returns false, an exception is thrown.

This leaves the most interesting thing: the Length Property Changed method. First of all, this has to be static in order to access it from a static method. Fortunately, the callback sends us the object, so we can call the instance version of the method as follows:

static void LengthPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {
(obj as MyClass).LengthPropertyChanged(args);
}

And Length Property Changed is just a regular old method that returns void. It is just that it gets called automatically whenever the Length changes.

Cascading Dependency Objects

This turns out to be incredibly easy to do. If the Dependency Object is of a type that is itself a Dependency Object, then the Change event gets triggered in either of two ways:

  • If you reassign a new object instance to the Dependency Object, this triggers the changed method because the entire object has changed.
  • If you change something within the dependency object, that triggers the changed method as well.

The example I tried was using a Point 3D Collection. Note that this is extended from Dependency Object. I used exactly the same patterns as for in the Length example above, except of course that the types are Point 3D Collection instead of double.

I found that the changed method was triggered if I assigned a completely new Point 3D Collection to the object. One would certainly expect that.

I also found that if I just added a point to the object, that too caused the changed method to run.

Note that changing an X, Y, or Z value on a particular point would not trigger the changed method because the Point 3D object is not a dependency object.

Setting up a Read-Only Dependency

Petzold’s book talks about Read Only Dependency Objects. An example of this is the Geometry property of the Shape Base class in my program. This is generated completely within each instance of the class and external programs simply read it. The constructor for the object initialized the value for the Geometry, but once this has been done, it is never changed. The collections within it are sometimes changed, but object holding the geometry is never changed. Therefore, there is no changed method defined for geometry; all the change methods are associated with the various parameters that can force an update to the geometry.

Why then should geometry even be a Dependency Object? The reason is that other 3D objects in the hierarchy are using this and watching it. If it changes, they have to run their own changed methods.

Here is the code that defines this read only Dependency Object:

public MeshGeometry3D Geometry {
protected set { SetValue(GeometryKey, value); }
get { return (MeshGeometry3D)GetValue(GeometryProperty); }
}

static DependencyPropertyKey GeometryKey =
DependencyProperty.RegisterReadOnly("Geometry",
typeof(MeshGeometry3D),
typeof(V3G_Shape_Base),
new PropertyMetadata(new MeshGeometry3D()));
public static readonly DependencyProperty GeometryProperty =
GeometryKey.DependencyProperty;

I got into trouble because I tried to use this pattern for a Point 3D Collection. It did not work. It turns out that I was making changes to the Collection, so this was not appropriate.

 

Applying Dependency Objects to Controls

The examples I found on this tend to involve their use with Controls. While these examples are interesting, they can also be a bit confusing since their emphasis is different. Here are some of the differences I found:

  • The control examples tend to use Framework Property Metadata instead of just Property Metadata. This metadata has lots more information than the simple Property Metadata that I am using, including something called Inherits.
  • Controls have a hierarchy that allows them to inherit values from higher level controls. For example, if a text block in a button has a font size property and the button has a font size property and the form has a font size, the font size that is actually used is selected from the most local control that actually has the property set. This is very important as regards controls and the Framework Property Metadata has some control over this, but I did not figure out whether this directly from Dependency Objects or from some fancy code somewhere in the classes between the controls and the Dependency Object class from which they are extended.

Thursday, August 11, 2011

NH Humane Society Event

Barbara and I went to the Humane Society Event. It was a disappointment for a number of reasons.

  • The event was very disorganized. It took a long time to hand them our tickets and check in. It took even longer to give them more money for things purchased at the silent auction and check out.
  • Parking was a mess.
  • We went with the idea that we would be fed. The event did start at 6:00 PM.  We were fooled. They did have people going around with hors d’oeuvres, but both of us were starving by the time we went into the dining room. And then there was no dinner.
  • It was boring with a long auction that we had to listen to before the comedians came on.
  • The comedians were OK, but not as funny as last year.

Don’t get me wrong – the event was not horrible and I had an OK time there. We bought bear candle holders at the silent auction and also a snake pin. BUT…

Bottom line is that it will not be necessary to attend this event next year.

Tuesday, August 9, 2011

Bike Ride Andover to Lebanon

Yesterday and today (Aug 8th & 9th), Jim Lerner and I rode our bikes from East Andover to Lebanon and back. I used my mountain bike and Jim used his hybrid.

At 10:00 AM, we started from the home of Alex and Myra Burnhard who have a lovely home there on a hill. We rode 1.4 miles down the hill to mile marker 43 on the trail. We had a nice, leisurely ride to Tewksbury pond where we stopped to eat the lunch Myra had made for us. We to there at about 1:15 and ate lunch by the side of the lake.

Barbara had agreed to meet us in Lebanon at around 3:00 PM. I had tried to phone her without success several times to tell her that we would be late. At 1:45, I decided to hurry to Lebanon so that she would not be waiting alone for us. I told the others to relax and take their time.

I finally got through to her on a bad connection and told her that I would be late. She headed to TJ Max in West Lebanon. I finally made it to Lebanon at 3:05 after doing the last 8.5 mile stretch in 35 minutes. I called Barbara and she got there at around 3:30. We then waited for the others until 4 or so. It turns out that Myra had had a leaky tire that required regular re-pumping.

We than all went to the Norwich Inn which turned out to be lovely. We there met Suzanne, a friend of Jim’s who joined us on the patio for drinks. Later we had a nice dinner (Suzanne had left) and retired to our lovely rooms.

The next morning, Barbara and I went to the King Arthur Flour store where we purchased a multi-tier spring form pan and some cake pan insulating straps. We met Jim for breakfast at the inn and had a hearty mean. Alex and Myra had eaten elsewhere at a spot where they loved the coffee.

We then all drove to Lebanon. Jim and I started out at 10:10. Alex had developed a sore the day before and decided not to ride, so Barbara drove the two of them home. Jim and I stopped in Danbury for a sandwich and finally made it back to chez Alex and Myra at 3:00 PM. His speedometer says that we had been riding for just under 4 hours.

By this time, we were both suffering from sore butts – mostly I think due to the very bumpy stretch from Danbury to Caanan or so. But all in all it was a pleasant excursion. It is a great ride and the Norwich Inn is a lovely getaway.

Sunday, August 7, 2011

Unsuccessful Pottery Firing

Yesterday, I fired a bunch of old green ware that I had thrown some time ago. I used the small kiln which I had not fired in two years. The kiln sitter did not trip and the kiln got overly hot, ruining (I assume) everything in there and not helping the kiln any either. But, with all failures, I learned a lot:

  • The cone that I put in the kiln sitter melted as it should have and the bar it was holding up dropped, but the switch did not fall. I think this was because it had corroded and gotten a bit stiff. I should have checked this before starting the kiln.
  • When I thought the kiln should have tripped, I should have checked the switch to see if it was stuck. I could have known long before that it was above the required temperature.
  • I should have had a triplet of pyrometric cones that I could have seen through a peep hole, so that I could have checked on the progress.
  • I have a pyrometer. I should have had it connected. Stupid. I need to set that up for next time.
  • I noticed bubbles in the resulting pieces. When I smashed them open, I found that indeed they did have air pockets in them. This could perhaps be an artifact of insufficient wedging. Perhaps also, no amount of wedging would have compensated for the possibility that I introduced the bubbles while trying to rejuvenate the clay after it had sat for too long.

Saturday, August 6, 2011

Hit Testing in 3D Graphics

I did some playing around with Hit Testing using the Visual Tree Helper class. Here are a few things that I learned:

  • The viewport mouse-down event does not fire unless the cursor is over a displayed triangle in the viewport. I am thinking it would be possible to place a large surface at end of the field of view opposite from the camera. There is no reason this could not be almost transparent.
  • It is easy to get the vertices of the triangle that was hit.
  • It is easy to get the point on the surface where the hit occurred.
  • You can the endpoints of a line along the cursor using the following code:

LineRange range;
ViewportInfo.Point2DtoPoint3D(_viewport, ptMouse, out range);

In the viewport mouse-down event, I put the following code:

base.OnMouseLeftButtonDown(args);
Point ptMouse = args.GetPosition(_viewport);

VisualTreeHelper.HitTest(_viewport, null, HitTestDown, new PointHitTestParameters(ptMouse));

I then created the HitTestDown call-back routine:

HitTestResultBehavior HitTestDown(HitTestResult result) {

    RayMeshGeometry3DHitTestResult resultMesh = result as RayMeshGeometry3DHitTestResult;
    ModVis3D vis = resultMesh.VisualHit as ModVis3D;
    string nl = Environment.NewLine;
    int Vertex1 = resultMesh.VertexIndex1;
    int Vertex2 = resultMesh.VertexIndex2;
    int Vertex3 = resultMesh.VertexIndex3;

    string sResult = vis.Generator.Name + nl;
    sResult += Vertex1 + " " + Vertex2 + " " + Vertex3 + nl;
    sResult += resultMesh.VertexWeight1 + " " + resultMesh.VertexWeight2 + " " + resultMesh.VertexWeight3 + nl;
    sResult += resultMesh.PointHit.X + " " + resultMesh.PointHit.Y + " " + resultMesh.PointHit.Z + nl;
    Model3D mod = resultMesh.ModelHit;
    if (mod is Model3DGroup) {
        sResult += "mod is Model3DGroup" + nl;
    } else {
        GeometryModel3D model = mod as GeometryModel3D;
        MeshGeometry3D mesh = model.Geometry as MeshGeometry3D;
        sResult += "Vertex1: ";
        sResult += mesh.Positions[Vertex1].X.ToString() + " ";
        sResult += mesh.Positions[Vertex1].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex1].Z.ToString() + " ";
        sResult += nl;
        sResult += "Vertex2: ";
        sResult += mesh.Positions[Vertex2].X.ToString() + " ";
        sResult += mesh.Positions[Vertex2].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex2].Z.ToString() + " ";
        sResult += nl;
        sResult += "Vertex3: ";
        sResult += mesh.Positions[Vertex3].X.ToString() + " ";
        sResult += mesh.Positions[Vertex3].Y.ToString() + " ";
        sResult += mesh.Positions[Vertex3].Z.ToString() + " ";
        sResult += nl;
       
    }
    SWF.MessageBox.Show(sResult);
    return HitTestResultBehavior.Stop;
}

Tuesday, August 2, 2011

Posting 3D Stuff to WarrenPClark.com

After cleaning stuff up for about a week, I posted what I hope is a workable set of information on 3D photography to WarrenPClark.com. I posted 2 pages of HTML – a default page and Photography.htm. I also posted three files that Photography.htm points to: 3Deifier.exe, BuildingAnOver-UnderStereoViewer.pdf and Viewing3dPhotosOnYourComputer.pdf.

3Deifier evolved from ViewMagic Viewer which it has completely replaced. For now, I have this saved in my dropbox.

The master documents are in dropbox/dev/3Deifier/Documentation.

Here is the list of the Documents I have regarding 3Deifier:

  • Building an Over/Under Stereo Viewer – Similar to ViewMagic™
  • Viewing 3d Photos on your Computer
  • Over Under Viewer.skp – Google Sketchup image of a single periscope
  • Specification.txt – a text document holding a list of critical tasks – not up to date.
  • Specification – Old.doc – an older specification. I think that Viewing 3d Photos on your Computer now makes a better specification than that does. The old one is unnecessarily verbose.

Sunday, July 31, 2011

Building an Over/Under Stereo Viewer

Introduction

This paper gives instructions for making an over/under stereo viewer. This is similar to the ViewMagic ™ viewer sold by Berezion.com and rmm3d.com. Note that it is a lot easier to just buy the ready-made unit, but if it is out of stock or if you want a different size viewer, this tells you how to make your own.
What you are building here is a pair of periscopes that you will mount together. One will allow the left eye to see an image three inches below eye level and the other will allow the right eye to see an image three inches above eye level.
The original of this file is stored as Building and Over-Under Stereo Viewer in the same directory as the specification for the 3Deifier.

Materials Required

Here is a list of materials required to make a viewer based on a 2” initial measurement. You can easily scale this up or down as desired. The original View Magic viewer seems to have been based on about 1.5”.
  • A 12” x 12” mirror tile. You can purchase a package of 6 of these from Home Depot for $10.
  • A ½” thick board at least three inches wide and at least 15” long. I used a scrap of ½” hardwood plywood.
  • A ¼” piece of plywood from which you will cut 4 pieces, each 3” x 7 ¼”.
  • 24 tiny nails – ¾” long.
  • 8 wood or sheet metal screws – about 1” long.
  • Some thick glue to hold the mirrors onto the backing plates.

Step 1 – Cutting the Side Boards

In this step, you will cut four diamond shaped boards that will make up the sides of the periscopes.
  • Set the rip fence on your saw for 2”. Cut a 2” wide piece from your ½ inch plywood.
  • Use a miter gauge to cut a 45” angle at one end like this:
clip_image002
  • Without moving the rip fence, cut 4 diamonds using the same 2” width. The resulting diamonds will be about 5 ¼” between the two sharp points. I tacked a small piece of scrap wood to each of the diamonds to make them easier to hold against the rip fence:
clip_image004

Step 2 – Cutting the mirror

You will need 4 pieces of glass. Two will be 6” by 2 ¾”. Two more will be 3” by 2 ¾”. You can purchase a glass cutter at the hardware store or Home Depot for $5. YouTube has a video named “Basic Glass Cutting” that explains how to do this if you don’t already know.

Step 3 – Cutting the Backing Boards

In this step, you will create the plates on which the mirrors will be glued.
  • Cut four rectangles from the ¼” plywood. Each should be 3” x 7 ¼”. If you used ¾” wood for the sides, increase the length of the plywood pieces to 7 ¾”.
  • Bevel the long sides of the plywood pieces to 45”.
  • Put ½” x 1/8” grooves in the short sides. The resulting pieces should all look like the following:
clip_image006
clip_image008

Step 4 – Trimming the Inner Backing Boards

In this step, you will cut out part of the inner backing boards. This allows the periscopes to be moved closer together so that you can use them both at the same time. I used a band saw for this, but you can do this on the table saw or with a hand saw. The piece I cut out is half-way in each dimension – in this case 1 7/16 x 3 1/8. Note the position of the bevel. It is very easy to cut out a wrong quarter.
clip_image010

Step 5- Assemble the Two Periscopes

Glue and nail the backing boards to the side boards. The side boards go on opposite sides of the two diamonds. Unfortunately, I forgot to take a photo of the two sub-assemblies before trimming the diamonds (which happens in the next step), but the photo below shows them after they have been trimmed. Sorry about that. . .
clip_image012

Step 6 – Trim Excess Side Board

At this point, your sub-assemblies will not look exactly like the ones above because the side boards are both still complete diamonds. Part of one diamond sticks out beyond the backing board cutout. We need to trim that. I used the table saw as shown below:clip_image014

Step 7 – Join the two Sub-Assemblies

Next we join the two periscope pieces together using 2 pieces of the ½” plywood cut to a 1’ width. One piece should be about 6” long and the other should be about a foot long. The longer one creates a handle. You can put the handle on either side – or both sides if you want. Drill holes in the pieces for the screws to go through:
clip_image016
The drill should be just large enough so that the screws you use will slide through easily.
Next you will connect the two subassemblies using these wood strips as shown in the image below. When doing this it is very important that the top and bottom edges are exactly perpendicular to the strips used to join them together. This is more important than having everything tight. I used the small square to line everything up before screwing it together.
clip_image018

Step 8 – Install the mirrors

You can use any kind of thick glue that will stick to glass. The viewer is shown below with the mirrors installed.
clip_image020
In this photo, you can see the two smaller mirrors. You can’t see the two larger mirrors. They are on the inner side of the ¼” thick backing pieces – the side you can’t see in the photo.

Step 9 – Try it out.

The easiest way to try this is with two prints – one from a left image and one from a right image. Place the right image 18 cm above the left image and look at them through the viewer. Your left eye should see mostly the left image and vice versa. You might have to adjust the images to optimize viewing. Once you have this working, you can try it on the computer. Use a viewing program to position the two images one over the other on your monitor. Of course, the easiest way to view them is with the 3Deifer software program, but that is a topic for another paper.

Step 10 – Variations

Now that you have built your first over/under viewer, you can try to build others with slight variations. The most obvious is to make viewers that are larger or smaller. I have a very large monitor, so I made one where I made the side pieces using a width of 2 ½ inches on my saw’s rip fence instead of 2” as in these instructions. This resulted in a viewing separation of about 17.75 cm which is a tiny bit too large even for my giant monitor. Note that the separation distance between the images goes with the square of the linear size of the side pieces. Don’t assume it is linear (as I did).
Another variation would be using different materials. I think it would be interesting to use very thick corrugated cardboard for the sides and thinner cardboard or corrugated plastic for the backing pieces. This would result in a lighter weight viewer and would not require the use of a table saw. I would be interested in hearing how this works out if anyone tries it. Or maybe I will.

Monday, July 25, 2011

Split .MPO file into left and right .JPG files

This morning, I got csharp code working that splits an MPO file from a Fujifilm FinePix Real3D camera into left and right components. Here is the code that does it.

using System;
using System.IO;
using System.Collections;

/// <summary>
/// Breaks an MPO file into two JPG files having names _L.jpg and _R.jpg.
/// Throws error if source file does not have .mpo extension.
/// Works by searching for 4 bytes: ff d8 ff e1 which is the start of both files.
/// Throws error if file does not start with ff d8 ff e1.
/// Throws error if other than one additional ff d8 ff e1 is found.
/// </summary>
/// <param name="sFullFileName">Full path to the .MPO file being split</param>
/// <param name="bOverwrite">If true, it will overwrite any existing left or right files. If false, it throws and error of the target files already exist</param>
public static void SplitMpoFile(string sFullPath, bool bOverwrite) {
    string sExt = sFullPath.Substring(sFullPath.Length - 4);
    if (sExt.ToUpper() != ".MPO") {
        throw new Exception(sFullPath + " does not have .MPO extension.");
    }
    string sFileNameBase = sFullPath.Substring(0, sFullPath.Length - 4);
    string sFileNameLeft = sFileNameBase + "_L.jpg";
    string sFileNameRght = sFileNameBase + "_R.jpg";
    if (File.Exists(sFileNameLeft)) {
        if (bOverwrite) {
            File.Delete(sFileNameLeft);
        }else{
            throw new Exception(sFileNameLeft + " already exists.");
        }
    }
    if (File.Exists(sFileNameRght)) {
        if (bOverwrite) {
            File.Delete(sFileNameRght);
        }else{
            throw new Exception(sFileNameRght + " already exists.");
        }
    }
      
    FileStream fs = new FileStream(sFullPath, FileMode.Open);
    long lFileLength = fs.Length;
    byte[] bytes = new byte[lFileLength];
    BinaryReader br = new BinaryReader(fs);
    br.Read(bytes, 0, (int)lFileLength);
    br.Close();
    fs.Close();

    // Verify that file starts with ff d8 ff e1
    if (bytes[0] != 255 || bytes[1] != 216 || bytes [2] != 255 || bytes[3] != 225) {
        throw new Exception(sFullPath + " does not start with correct code.");
    }
    // Make an array list of all the places in the file that start with ff d8 ff e1
    ArrayList alBreakPoints = new ArrayList(8);
    for (int i = 1; i < lFileLength - 4; i++) {
        if (bytes[i] == 255 && bytes[i + 1] == 216 && bytes[i + 2] == 255 && bytes[i + 3] == 225) {
            alBreakPoints.Add(i);
        }
    }
    // At this point, there should be exactly 1 element in the array list.
    if (alBreakPoints.Count != 1) {
        throw new Exception(alBreakPoints.Count + " breakpoints found in " + sFullPath);
    }
    int iBreakPoint = (int)alBreakPoints[0];

    // OK - everything looks good here. Output the two parts of the file.
    fs = new FileStream(sFileNameLeft, FileMode.CreateNew);
    BinaryWriter bw = new BinaryWriter(fs);
    bw.Write(bytes, 0, iBreakPoint);
    bw.Close();
    fs.Close();
    fs = new FileStream(sFileNameRght, FileMode.CreateNew);
    bw = new BinaryWriter(fs);
    bw.Write(bytes, iBreakPoint, (int)lFileLength - iBreakPoint);
    bw.Close();
    fs.Close();


}

Saturday, July 23, 2011

Saved my Paella Recipe

Today, I managed to enclose the area above the double doors in the new pottery studio. I used mostly 5/4 pine scraps to do this, but for the last piece, I cut down a scrap piece of 2x8.

I also wrote out the recipe I have been using for paella. I saved this to Documents\hobbies\recipes\paella.txt.

Here we go

I am starting this blog with the idea that it is primarily for my personal use, but others are welcome to visit and learn. I want to use it as a journal where I can save notes as to what I am doing and more importantly, how I do things that I might have to do again someday. The advantage of a blog (I am told) is that I can post either directly or via email from my cell phone and later I can search for entries that I might have made weeks, months or years previously.