Friday, November 8, 2013

Chameleon Arch - Doctor Who Themed Animated Clock

In anticipation of the Doctor Who 50th Anniversary, I've put together a Chameleon Arch inspired clock program.  It is built in JavaFX and requires at least Java 7 to run.  Downloads can be found at the bottom of this post.

Demonstration Video:


The plan was just to make an animated clock.  Eventually ended up having so much fun that I added sounds, time dilation/contraction/reversal, and a TARDIS themed user interface.  If any programmers are interested in the source code or have any questions/comments let me know and I'll do my best to answer.

Should run fine on Windows, Linux, and Mac.  Requires at least Java 7!

Update: Just Tried to run this on a Sandy Bridge i5 with integrated graphics.  I would not recommend anyone try to repeat this.  Five frames per second makes everything look pretty pathetic.  I may try to pre-render the background animations to alleviate processor load.

I haven't made pretty launchers for Mac and Linux like I have for Windows, but the .jar file should work perfectly fine for those platforms.  Let me know if you encounter any problems.

Downloads
Windows Installer (Start menu entry + README)  ▼ Chameleon Arch Setup.exe
Windows Executable▼ Chameleon Arch.exe
Multiplatform Jar▼ ChameleonArch.jar


Currently Known Bugs v1.0:
(These are caused by my code being a bit wibbly-wobbly timey-wimmey, I need to play around a bit more with Executors and Service classes to fix them.  In the mean time we'll call them features)
  • The playback rate for sounds at extremely low time speeds does not sync up nicely with the animation.  We'll say this is because passing too close to the walls of the time vortex causes anomalies, couldn't be a double rounding/bitrate issue or lax coding, nope!
  • Sounds triggered at extremely low speeds will continue through a full playback even after the time has been sped up.
Sources
Base image for the background animation --- Jake Hildebrandt:
http://jakehildebrandt.com/

Minute and hour hands base image:
http://www.clker.com/clipart-watchhands-clock-hands.html

Tick sound --- Louis Bartlett:
http://freesound.org/people/DrMinky/

TARDIS sound effects:
Rights to these sounds belong to the BBC © 1963
http://biodoctor900-whovianmadness.weebly.com/odds--sods.html

Legal Stuff
This software was developed by Kristofer Weisshaupt. 

Rights to Doctor Who intellectual property belong to the BBC.  I am not associated with the BBC and did not intend any copyright violation.    This post and its contents are for educational/nonprofit purposes.

This software is provided free of charge "as-is," without any express or implied warranty.  In no event shall the author be held liable for any damages arising from the use of this software.

Please contact me before redistributing or reusing any of my code/projects.  A citation in the following format would be greatly appreciated:

"___<Component Used>___ courtesy of Kristofer Weisshaupt http://nooleanbot.blogspot.com/"

Tuesday, August 27, 2013

PictoStencil --- Image Manipulation Software

This month I've been working on an image processing application that takes images and converts them to fully supported, contiguous stencils for woodworking, paper-craft, jack o' lantern carving, and more.  It can do this either automatically, or through a guided process.  I'd hoped to finish it before September hit, not happening.  Figured I'd throw up a post describing some of what I have so far.


I'm continuing to use my custom JavaFX windows.  I'm using a much lighter color scheme this time around.  I've written algorithms for Color Balance, Gaussian Smoothing, Otsu Binarization, Sobel Edge Detection, as well as some binary morphological image transforms (Manhattan dilate&erode, close, open, invert, edge find, Tarjan connected component search).  There are so many cool mathematical operators out there for applying to images.  I really want to keep going, but I think I'm going to refrain from writing any more myself.  I'd really like to have Fourier band pass filtering.  Might go back some time and incorporate a few of OpenCV's free to use image operations.

I also had to write custom code for the paint tools.  They've been problematic.  I'm using a JavaFX Canvas for the working area and it loves to anti-alias everything.  There are no rendering hints that would allow me to customize this behavior.  I'll make a post if I find a way around this, but at the moment it appears I'll need to try some other option.

I'll try to get a video and .jar file up some time in September/October.  That way it'll be useful for making custom jack 'o lantern patterns.  I shouldn't have to write installers unless I start incorporating native libraries.

Update:  Haven't done any more work on this project.  I might come back to it once I've played around with Java 8 some more.  At the moment though there are enough minor canvas problems that they've added up to kill my initiative.

Saturday, July 20, 2013

MAS-345 Digital Multimeter Data Acquisition Software


I recently finished up a data acquisition program for the MAS-345 Digital Multimeter.  I used my custom JavaFX windows from an old project, styled to match the meter itself.  The meter is sold under several brands including Mastech, RSR, and Sinometer.  The original software will not run on 64 bit systems so I've written this program to provide support for modern computers.  The project was built in JavaFX and uses the RXTX library for RS232 serial port communication.  If you're a programmer with questions about these tools, ask away.  I'll try my best to answer.

A demonstration of the use and features of the data acquisition program can be seen in the video below.



This program should run on Windows, Linux, and Mac.  Some fiddling may be required on Linux and Mac to get RXTX installed properly (So far I've only tested it on Windows 7 x64).  The Windows installer available below should make installation on Windows operating systems fairly easy.  See the included README.txt for additional installation info and RXTX downloads.

NOTE: It is essential that you match your OS Architecture, Java JRE, and RXTX versions.  Running 32 bit Java on a 64 bit system will prevent RXTX from functioning!

Huszty Gergo created a C# version a while back.  His program inspired me to go ahead with this project.  Try his out if you have problems fiddling with RXTX or I somehow break something in mine.

Downloads
Windows Installer (x86, x64, ia64) ▼ MAS-345 Setup Windows.exe
Multiplatform Jar (requires user to download and set up RXTX) ▼ MAS-345 Multiplatform JAR.jar


RXTX binaries courtesy of Mfizz Inc.
Digital-7 font created by Style-7

Sunday, June 9, 2013

Logitech G13 as Keyboard+Mouse Replacement

I recently spent some time looking into computer interface devices for a 9 year old who only has use of his left hand.  The kids his age are really into Minecraft, a game that typically requires two hands whether played on the PC or Xbox 360.  I figured that this was one activity that he most certainly could enjoy with his peers; so I got to work.  It gave me a chance to play with some new toys and tinker with modding/coding so it was a win-win!

I looked into a few different devices.  If you want to skip the rest of this article and just start researching potential solutions here's some of the options I considered:

  • Keypad Gaming Mice (Razer Naga and Logitech G600)
  • Gamepads
  • Modified Controllers
  • Motion Capture Controllers
  • Joysticks
  • Leap Motion
  • IR camera +  pupil tracking

I haven't tried out a Leap Motion yet, I think they have the potential to be great for those with limited motor control.   I may apply for a development kit if they're still available.

I eventually decided that a Keypad Mouse like the Razer Naga or Logitech G600 would work best.  Sadly neither company has a left handed version yet (Razer announced they would make a left handed version in March 2013).  Instead I picked up a Logitech G13 gamepad.  I went with Logitech over the Belkin and Razer options because it is the only gamepad I found with a true analog thumbstick.  The other gamepads have a Directional-Pad (either 8 way or 4 way).  The analog stick seemed to be the better option for replacing mouse control.

I recorded a few of the setups I tried out.  They can be seen in the video below.



I started playing with Lua scripting to create more complex behavior than can be achieved with the standard Logitech macro editor.  The only experience I'd had with Lua was some game add-on debugging a few years ago, so it was a bit of a slow start.  One of my first tasks was to emulate a mouse wheel using the two keys near the thumbstick.  My first attempt resulted in the code below which uses Logitech's built in event handler.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
KEYMAP = {
     [23] = function(n) fn_WHEEL_UP(n) end,
     [24] = function(n) fn_WHEEL_DOWN(n) end,
}

REPEAT_DELAY = 100

function OnEvent(event, arg, family)
     if event=="PROFILE_ACTIVATED" then 
          ClearLog()
          OutputLogMessage("Script Started.\n")
          wheel_up = false
          wheel_down = false
     end
     if family == "lhc" then
          local action = KEYMAP[arg]
          if type(action) == "function" then 
               action(event)
          end
     end
     if event=="M_PRESSED" and wheel_up then
          RepeatWheel(1)
     elseif event=="M_PRESSED" and wheel_down then
          RepeatWheel(-1)
     end
end

function fn_WHEEL_UP(event)
     if event == "G_PRESSED" then
          wheel_up = true
          RepeatWheel(1)
     elseif event == "G_RELEASED" then
          wheel_up = false
          MoveMouseWheel(0)
     end
end

function fn_WHEEL_DOWN(event)
     if event == "G_PRESSED" then
          wheel_down = true
          RepeatWheel(-1)
     elseif event == "G_RELEASED" then
          wheel_down = false
          MoveMouseWheel(0)
     end
end

function RepeatWheel(movement)
     OutputLogMessage("Moving Wheel: %d\n", movement)
     MoveMouseWheel(movement)
     OutputLogMessage("Delaying Wheel DOWN: %d\n", REPEAT_DELAY)
     Sleep(REPEAT_DELAY)
     SetMKeyState(GetMKeyState("lhc"),"lhc")
end

This code uses setting of MKeyState to repeatedly fire events while the key is held down.  It works, but it runs into event pileup problems with sleep delays larger than a few milliseconds.  Trying to mouse wheel up and down in quick succession will result in a queue of events and a laggy user experience.  Some helpful people in the Logitech support forums pointed me towards llProject, a Logitech device polling library which solves a lot of common problems and allows for some pretty complex macros.

The llProject library was very well documented and easy to figure out.  I was able to create an emulated mouse wheel with a very nice feel.  I set it up to do an immediate tick of the wheel, followed by a large intitial delay before going into a steady repeat as long as the key is pressed.  Instead of sleeping for a delay, preventing all queued tasks from executing, llProject routines yield activity and the routine manager continually checks to see if the necessary delay has passed before continuing the yielding process.  This allows some routines to continue while delaying others.  Here's the code I ended up with:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
--------------------->
ll=ll or {}; ll.SETUP = { Folder = [[C:\Logitech Scripts\llProject\]] }
dofile(ll.SETUP.Folder .. [[llProject.lua]])
-- llProject End -->

M_PROFILE = 0
INITIAL_DELAY = 300
REPEAT_DELAY = 100

function _onActivation()
     ll.lhc.map[M_PROFILE] = {
          [23] = fn_WHEEL_UP,
          [24] = fn_WHEEL_DOWN
     }
     initialUpTick = ll.Routines:Create(fn_WHEEL_TICK,1,INITIAL_DELAY)
     repeatUpTick = ll.Routines:Create(fn_WHEEL_TICK,1,REPEAT_DELAY)
     initialDownTick = ll.Routines:Create(fn_WHEEL_TICK,-1,INITIAL_DELAY)
     repeatDownTick = ll.Routines:Create(fn_WHEEL_TICK,-1,REPEAT_DELAY)
end

function fn_WHEEL_UP()
     if ll.Event.Pressed then
          initialUpTick:Restart()
          return
     end
     if ll.Event.Down and initialUpTick:IsDead() and not repeatUpTick:IsRunning() then
          repeatUpTick:Run()
     end
     return
end

function fn_WHEEL_DOWN()
     if ll.Event.Pressed then
          initialDownTick:Restart()
          return
     end
     if ll.Event.Down and initialDownTick:IsDead() and not repeatDownTick:IsRunning() then
        repeatDownTick:Run() 
     end
     return
end

function fn_WHEEL_TICK(direction, delay)
     MoveMouseWheel(direction)
     Sleep(delay)
end


Feeling the mouse emulation and key layout were as good as I was going to get them, I moved towards physically modifying the G13 for easier use.  I found the original G13 thumbstick to be uncomfortable and difficult to use.  It is narrow enough that your thumb can very easily slide off if it isn't perfectly centered.  Like many others, I decided to replace it with the thumbstick from a game controller.  Xbox 360 thumbsticks are nearly a perfect fit.  The only modifications necessary are widening the G13 case's thumbstick pass-through, and narrowing the 360 thumbstick's mounting hole.

I didn't have any epoxy to fill the mounting hole, so instead I drilled it out wider and glued in a section of 3/8th inch dowel.  I then drilled out and lengthened a new mounting hole with a 1/64th inch drill bit.

The thumb portion and the support peg of the 360 thumbstick are much wider than the original.  In order to achieve the same range of motion (and get the peg through the top of the case) you have to widen the case's thumbstick pass-through hole.  I started out trying to do this with a dremel, but found it cut too unevenly and was much too aggressive.  I gave up on the dremel and instead drilled the hole out to 3/4 inch with a Forstner bit.  After cleaning up the cut with some 200 and 400 grit sand paper I ended up with a nice clean edge as seen in the images below.





Wednesday, May 29, 2013

Wooden Comb Finished

This is a continuation of the project shown here.

I finally got the finish work on the Bloodwood + Red Oak comb done.  I chose 100% Pure Tung oil for the finish so I had to wait at least a day or two between coats.  The oil smells a bit like peanuts, but it undergoes an oxidative chemical reaction as it dries and the smell goes away.  I went with tung oil because of its water resistance, non-toxicity, ability to be reapplied, and oxidative drying.  Tung oil does come from a nut, so if you're building for someone with nut allergies maybe consider linseed oil.  I was hesitant to use a nondrying oil because it just seems like it would be a little gross to be oiling your hair as you combed it (smelly too).  It is possible that you could just let the comb oil itself with human oil (shudder) as it was handled, but you'd have to take great care not to expose it to moisture.  I decided against doing any sort of enamel or spray finish because I didn't think it would hold up to repeated handling.


Here it is right after applying the 4th and final (so far) coat, direct light really brings out the red, in the dark it looks purplish:


I was applying successive coats with 600 grit wet-use sandpaper.  The oil mixes with tiny bits of the bloodwood to create a red slurry that looks really cool once it gets into the pores and holes. I let it dry a week and a half and then buffed it out with a cloth.  I'm pretty happy with the results, though I do wish it was more red.

I'm considering selling these, custom made.  I don't really want to build the same thing over and over (easy and cheap, but not very fun).  I have some cool ideas for potential variations and wood combinations.  Luckily the cost of the materials is fairly low, but they'd still be pretty pricey, a lot of time goes into them.  I've been wanting to build a CNC machine, I'd probably do that if I had to make a lot of these.  If you're interested drop me an email at nooleanbot@gmail.com and we can discuss woods, finishes, ect.  Would be pretty easy to incorporate wood/designs from an old family property or decaying heirloom too, might as well make things extra personalized.

More pictures below.  Since taking these pictures I've gone back with a needle and some glue and carefully filled some of the holes that developed around the inserts during the sanding and finish work.  Direct sunlight really brings out the red, sadly the pics below were taken under overcast conditions.





Sunday, May 19, 2013

Google Charts Tips

I incorporated a few Google Charts into a recent project.  I wrote some code to automatically write the chart javascript using data extracted from an SQL database.  I found the Google Charts API well documented and fairly easy to use.  However, I did encounter a few issues that I think merit addressing.

Here's an example of a highly customized graph that makes use of some of the more involved chart options.



This graph contains a secondary vertical axis, an option not demonstrated in the Google examples.  Also used are date, number, and tool-tip formatting.  Notice the formatted numbers on the mouseover tooltips for the first set of data points (May 1st) compared to the default formatting on the other points.  The code below will generate the graph as seen above.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<div id="history_div" style="width: 730px; height: 400px; margin: 0;"></div>

<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    google.load('visualization', '1.0', {'packages':['corechart']});
    google.setOnLoadCallback(drawVisualization);
    function drawVisualization() {
        var data = new google.visualization.DataTable();
        data.addColumn('date', 'Date');
        data.addColumn('number', 'Cost Total($)');
        data.addColumn('number', 'Sell Total($)');
        data.addColumn('number', '# of Products');
        data.addRows([
            [new Date(2013,4,1), {v: 90000.00, f: '$90,000.00'}, {v: 140000.00, f: '$140,000.00'}, {v: 8000.00, f: '8,000'}],
            [new Date(2013,5,1), 100000, 160000, 10000],
            [new Date(2013,6,1), 130000, 200000, 14000],
            [new Date(2013,7,1), 95000, 150000, 9000],
            [new Date(2013,8,1), 95000, 150000, 9000]
        ]);
        var options = {
            pointSize: 2,
            width: 730,
            height: 400,
            vAxis: {
                baseline: 0,
                gridlines: {count: 8}},
            vAxes: [
                {title: 'Value ($)', format: '$###,###,###', textStyle: {color: '#088A08'}},
                {title: '# of Products', format: '#', textStyle: {color: '#0000FF'}}],
            hAxis: {
                title: "Date", 
                format: 'M/d', 
                gridlines: {count: 8}},
            series: {
                0: {type: "line", targetAxisIndex: 0, color: '#21610B'},
                1: {type: "line", targetAxisIndex: 0, color: '#5FB404'},
                2: {type: "line", targetAxisIndex: 1, color: '0000FF'}}, 
            chartArea:{
                width: "75%", 
                height: "75%"}    
        }
        var chart = new google.visualization.ComboChart(document.getElementById('history_div'));
        chart.draw(data, options);
    }
</script>

Secondary Vertical Axis:  Created using the vAxes option.  We can then tell the # of Products data series to use the secondary axis using the targetAxisIndex in the series configuration as shown in line 37.

Formatted Data Values:  Declared using the {v: VALUE, f: 'FORMATTED VALUE'} notation.  An example of formatting tooltip numbers is shown in line 14.

Dates:  Created using Date(Y,M,D) remember that javascript months count from 0-11.

Component Overlapping Bug:  
The image below shows another problem you may encounter while implementing Google Charts.  The overlapping of the chart entities is the result of the chart not being visible at the time of its loading.  In my case it was in a div that was hidden at the time of page load.  Ensure that the chart is visible at the time of its loading (at least for a few milliseconds) in order to fix this problem.


I had some problems trying to get the graph to size itself correctly in browsers other than Chrome.  I haven't been able to reliably reproduce the problem  (so it may have just been a typo on my part), but it seems that as long as you declare a size both in both your div styling and the chart options the chart will render correctly.

Tuesday, April 30, 2013

Inventory Management Software



A while back I created some custom inventory management and pulling software for an old employer.  I recently went back and added some new features for them.  The project has developed into a fairly full featured cool little piece of software, much more-so than I had envisioned when I started it.  I took on the project when it became clear that the client needed a better way of organizing and pulling stock, but didn't want to transition to a new point of sale system or pay the fairly high quotes for integrating a more standardized inventory setup.  I managed to create a system which would allow them to stick with their current POS program, use their existing barcode scanners, and request products from an iPad (or other web browser).

The project pushed me to break into some languages and libraries I hadn't played with in the past.  At points during development I made use of: Java, SQL, HTML, CSS, Javascript, ODBC, Derby, Google Charts, plus a bit of work in MS Office and Adobe CS6.  It would have been nice to have stuck with Java for more of the project, but a substantial portion of its use was going to be done on iPads which lack Java support (sadly this was before the rise of Android).  Instead I went with a locally served webpage for requesting products from the iPad.

I originally had my program pulling the product info out of the client's point of sale system and storing it in a separate database in Microsoft Access.  I hadn't ever edited an office file programatically before (or even used MS Access), so that was pretty fun to learn.  I went with MS Access because it allowed me to quickly develop the project, without having to build database management features into my user interface.  Eventually  I decided that for the sake of simplicity, ease of use, and program independence I would move the database entirely over to Java using a derby database.  Providing the user the ability to change, remove and add values to the database in a graphical form was a bit of a pain; my go-to solution was to use Swing's JTables which are pretty convoluted and difficult to work with.  I've since moved away from Swing in favor of JavaFX which has been a vast improvement.

I'm a bit of a novice when it comes to web development so I tried to keep things as simple as possible.  There is no server side scripting or direct linking to the database, instead the page is updated once or twice a day and everything is handled in simple HTML and Javascript.  Form data is collected client side in local storage and emailed using a mailto link.

My most recent updates added the capabilty to track the monetary value of the inventory assets.  I decided to go ahead and toss in some Google Charts for visualizing cost breakdown by category and assets over time.  I found Google Charts to be well documented, very pleasant to use, and fairly consistent across all the major browsers.  I've written a separate post on some of the tricks I discovered to getting the expected behavior out of the charts.  The Google Charts post can be found here: http://nooleanbot.blogspot.com/2013/05/google-charts-tips.html

Thursday, April 25, 2013

G15 Keyboard to 5.5" Drive Bay

I recently replaced my long-used Logitech G15 v2 with a Ducky mechanical keyboard.  So far the only thing I've missed is being able to see CPU, GPU, and RAM status just by glancing at the keyboard.  I decided to see how feasible it would be to convert my G15 into a front panel display.  I haven't started the build yet, but this is what I've come up with so far:



There aren't any components in the areas of the  LCD PCB that need to be cut away, and the only parts nearby seem to be some LEDs for back-lighting.  So as long as I'm careful, it should be possible to cut them away without affecting function.

Five of the front panel buttons are the app control keys mapped out as shown in the photo below.  I added volume controls to fill out the rest of the front panel.
Figure 1: G15 App Keys.  These 5 keys will be included on the front panel as labeled.

If you attempt this build at the minimum you'll need:
  • Case from old optical drive
  • 2mm ABS plastic
  • 8 Cherry MX Switches
  • ~1 meter Cat 5 Ethernet cable
  • ~23 cm of 33 pin VM 2896 ribbon or 8 meters of ~30 gauge wire :P
  • Black Spray Paint
  • Glue, possibly Alumilite
  • Ability to cut, drill, and solder 

Inside the G15, underneath the rubber domes and key switches is a sheet of clear plastic for transmitting the LED light throughout the keyboard.  This plastic should be enough to build up the clear components of the mod, including the keycap faces.  I plan on using clear Alumilite, or glue to form the columns that connect the keycaps to the switches.  It is probably a good idea to add a metal cutout behind the keys so that they bottom out against something solid, rather than pushing against the already compromised LCD PCB.  The Cherry MX Blue switches only need about 2.5 mm of travel to activate, so it should be feasible to include a 1 mm bottom-out plate without pushing the LCD back too far.

I plan on using a chunk of the G15 case to mount the main PCB to the drive case.  I'll just run the USB cable out the water cooling grommets to the back of my computer case.  I left a cutout in the lower portion of the switch mounting plate to allow light from one of the G15's LED arrays to shine through if I decide I want additional back-lighting.

Wiring Pin-out:

Below is the PCB I've set up to carry the switch inputs to the LCD ribbon socket.  Sadly it isn't easy to achieve the necessary connections in a single layer; the grey lead either has cross over as shown below or go on a long meandering path around the edges.  It is probably easier just to use some Cat 5 cable soldered to the switches and plugged into the LCD ribbon socket.
Figure 2: Switch PCB.  This PCB collects switch leads to be routed to the PCB ribbon input.

The mute button does not connect to the LCD PCB like the rest of the switch leads, instead it connects to the main PCB. The picture below shows where to attach the mute button leads.
Figure 3: Main PCB.  Shows the inputs for wiring the mute button.


Saturday, March 30, 2013

Wooden "Viking" Comb

I've been growing a beard and decided it would be fun to have a wooden beard comb.  I looked around for examples and found this instructable.  It looked like a fun little project so I decided to do a quick run through and see what I could come up with.

The only part of the instructable I used was the scraping tool he made to file down the teeth.  I crafted the scraper out of a reciprocating saw blade, but ran into problems when I went to use it.  I think I may have overheated and untempered the steel when I filed it down using a disc sander.  The edge fell apart when trying to use it and I had to resort to other options.

I eventually managed to rough out a comb for myself, then my sister saw it and decided she wanted one.  I was using red oak for the comb portion and told her to take her pick of woods to make the handle.   She grabbed a nice piece of contrasting bloodwood.  This was my first time working with bloodwood, the stuff is HEAVY and extremely hard.  The first time I ran the stock over the jointer it sounded like I was trying to cut a metal beam (pretty sure I chipped a blade, shhhh don't tell my stepdad!).  Since I was using some exotic wood, I decide to make things a bit fancier.  I eventually decided on a coved design with a curved handle.

Going into this project without a plan was extremely fun. I just sort of winged everything free hand and decided on the next steps as I went.  Hadn't originally intended on making a case for it, but once I had the comb roughed out I decided it merited one.  I ended up planing down an old oak cabinet door to 1/4 inch for the main part of the comb.  Oak is fairly hard, and extremely porous, so perhaps not the best choice for making fine cuts.  However, oak has cool primal connotations (at least for me) and the pores will likely help with distributing oils, which is the main benefit of using wooden combs.

I found that the easiest way to form the teeth was to:
  1. Put a tapering cove on the tooth area using an oscillating spindle sander (could also be done with the end of a belt sander, or an oscillating orbital sander).
  2. Cut straight teeth on a bandsaw (I used 3/16" spacing on center between cuts).
  3. Taper the teeth, again on the bandsaw. 
  4. Using a 1/4" chisel, round and taper the teeth by hand (time consuming, but end result is great!)
  5. Fold up some sand paper and either sand between teeth by hand, or mount the sand paper in a scroll saw to take down the bandsaw blade marks quickly.
It might be a good idea to space the teeth out more, perhaps use a table-saw to make the spacing cuts so that there is a full 1/8th inch between teeth.  The comb works fine as it, but I've read that women prefer wider spaced teeth so that they can more gently tug out snags.  If I were to make more of these I'd probably build a rotating tapering bit that I could chuck into a drill.  Would make things much faster and would hopefully result in a smoother shape and less sanding.


I considered putting some 1/4" neodymium magnets in the case and running stainless-steel wire down the outer parts of the comb so that it would lock itself in place, but the amount of pull the magnets had on that tiny amount of metal was pretty minimal.  I decided against using magnets and instead relied on friction to hold the comb in place.  Worked out perfectly fine.

The runes cut into the case are the 5th-10th century anglo-saxon alphabet known as futharc.  I cut them out by hand on a scroll saw table, pretty time consuming, made me wish I had a CNC machine, maybe I should make one.  The runes phonetically spell out my little sister's name.  According to some sources the runes each have their own meaning in addition to their phonetic sound, usually corresponding with the shape and sound of the letter.  In this case the meanings of the runes work out to Torch-Ash-Thorn-Ride-Bow-Need.  We were pretty excited to have the "bow" rune in there, traditional archery is one of our family's favorite hobbies.

Getting decent fits on the oak inserts wasn't as difficult as I feared it would be.  I ended up just cutting some long strips of oak and then sanding them down with a block sander until they had a slight taper.  Then I'd push the oak as far as I could into the cut, mark it, and cut it to length.

Here's what the comb looks like currently.  I still need to do a lot of rounding, sanding, and oiling.  I'm liking it so much that I wish it had my name on it.

________________________________________________________________________________________

Update:  I applied 4 coats of 100% Tung Oil finish.  To check out the results click here!






Wednesday, February 20, 2013

Custom JavaFX Windows


I've been learning JavaFX and decided to make a Pane wrapper to create custom windows for JavaFX applications.  By default your choices are to use the standard OS window, a minimalist OS window, or an undecorated window (no window encapsulation at all).  I like having full control over the window behavior and appearance so I've set up a StackedPane which will surround your content pane (Client Area in the image above) with a CSS customizable pane with the usual window features.  Shown below is a quick little example with some very simple styling.


The resize and movement behavior is achieved using regions that have been set up in the scene builder as shown to the right.

Below is a video of some of the behavior in action as well as a look at the controller for the window functions.  There have been a few changes since I made that video.  The biggest change is that I switched from extending Stage to extending StackPane, this change makes life a lot easier down the road when trying to deal with inheritance.

I still need to add window snapping and the ability to restyle the window on maximize (e.g. get rid of rounded corners).