Pages Menu
TwitterRssFacebook
Categories Menu

Posted by on 27th September, 2009

Another Clock experiment

Another Clock experiment

I seem to be unable to break free form any projects that are somehow related to clocks or watches. This time I saw a YouTube movie about an unique clock with a very creative way of displaying time.

It is a design is by Sander Mulder and can be seen here: Continue Time Clock. It allows a single arm that is segmented in three parts, to show the hours, minutes and seconds with each correspondent segment at the same time, and although it may not be very intuitive, it is extremely creative and elegant at the same time.

Here is my attempt at re-creating the mechanism of this clock in Silverlight 3.0 …

Get Microsoft Silverlight

It turned out to be relatively simple, by creating a class for each arm and let the hour arm class contain an instance the minute arm class and the minute arm class an instance of the second arm class.

This way I could just spin them around their RenderTransformOrigin and they would maintain their relative position at the tip of their parent arm.

mainpage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace silverlight_clock_singlearm
{
 public partial class MainPage : UserControl
 {
  public static double armHourAngle;
  public static double armMinuteAngle;
  public static double armSecondAngle;
  private Storyboard StoryBoard = new Storyboard();
  private ArmSecond armSecond;
  private ArmMinute armMinute;
  private ArmHour armHour;

  public MainPage()
  {
   InitializeComponent();
   this.armSecond = new ArmSecond();
   this.armMinute = new ArmMinute(this.armSecond);
   this.armHour = new ArmHour(this.armMinute);
   this.Canvas_Root.Children.Add(armHour);
   TranslateTransform translateTransform =
    new TranslateTransform();
   translateTransform.X = 200;
   translateTransform.Y = 50;
   this.armHour.RenderTransform = translateTransform;
   this.StartClock();
  }
  private void StartClock()
  {
   this.StoryBoard.Duration = TimeSpan.FromMilliseconds(1);
   this.StoryBoard.Completed +=
    new EventHandler(StoryBoardSeconds_Completed);
   StoryBoard.Begin();
  }
  private void StoryBoardSeconds_Completed(object sender, EventArgs e)
  {
   DateTime now = DateTime.Now;
   armHourAngle = this.armHour.setAngle(now);
   armMinuteAngle  = this.armMinute.setAngle(now);
   armSecondAngle  = this.armSecond.setAngle(now);
   this.txtTime.Text     = "Time: " + now.ToLongTimeString();
   this.txtHourAngle.Text = "HourAngle: " +
    armHourAngle.ToString("0.00");
   this.txtMinuteAngle.Text = "MinuteAngle: " +
    armMinuteAngle.ToString("0.00");
   this.txtSecondAngle.Text = "SecondAngle: " +
    armSecondAngle.ToString("0.00");
   StoryBoard.Begin();
  }
 }
}

armhour.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace silverlight_clock_singlearm
{
 public partial class ArmHour : UserControl
 {
  private RotateTransform rotateTransform =
    new RotateTransform();
  public ArmHour(ArmMinute _armMinute)
  {
   InitializeComponent();
   this.CanvasArmHour.Children.Add(_armMinute);
  }
  internal double setAngle(DateTime _now)
  {
   int _hour = _now.Hour;
   int _minute = _now.Minute;
   double hourFull = (double)_hour * 30.00;
   double hourFraction = (double)_minute * 0.50;
   this.rotateTransform.Angle = hourFull + hourFraction;
   this.CanvasArmHour.RenderTransform = rotateTransform;

   //adjust the face so it stays straight to the viewer ~~~~~~~
   TransformGroup FacePlateMinuteTransformGroup = new TransformGroup();
   TranslateTransform translateTransformFacePlateMinute =
     new TranslateTransform();
   translateTransformFacePlateMinute.X = -72;
   translateTransformFacePlateMinute.Y = -47;

   RotateTransform rotateTransformFacePlateMinute = new RotateTransform();
   rotateTransformFacePlateMinute.Angle = 360 - this.rotateTransform.Angle;
   FacePlateMinuteTransformGroup.Children.Add(rotateTransformFacePlateMinute);
   FacePlateMinuteTransformGroup.Children.Add(translateTransformFacePlateMinute);
   this.FaceMinute.RenderTransform = FacePlateMinuteTransformGroup;
   return this.rotateTransform.Angle;
  }
 }
}

armminute.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace silverlight_clock_singlearm
{
 public partial class ArmMinute : UserControl
 {
  private RotateTransform rotateTransform = new RotateTransform();
  private RotateTransform rotateTransformFacePlate = new RotateTransform();
  public ArmMinute(ArmSecond _armSecond)
  {
   InitializeComponent();
   this.CanvasArmMinute.Children.Add(_armSecond);
   TranslateTransform translateTransform = new TranslateTransform();
   translateTransform.X = 2.5;
   translateTransform.Y = -53;
   this.RenderTransform = translateTransform;
  }
  internal double setAngle(DateTime _now)
  {
   int _minute = _now.Minute;
   int _seconds = _now.Second;
   double minuteFull = (double)_minute * 6.00;
   double minuteFraction = (double)_seconds * 0.1;
   this.rotateTransform.Angle = minuteFull + minuteFraction - MainPage.armHourAngle;
   this.CanvasArmMinute.RenderTransform = rotateTransform;

   //adjust the face so it stays straight to the viewer ~~~~~~~
   TransformGroup FacePlateSecondTransformGroup = new TransformGroup();
   TranslateTransform translateTransformFacePlateSecond = new TranslateTransform();
   translateTransformFacePlateSecond.X = -54;
   translateTransformFacePlateSecond.Y = -24;
   RotateTransform rotateTransformFacePlateMinute = new RotateTransform();
   rotateTransformFacePlateMinute.Angle =
    360 - this.rotateTransform.Angle - MainPage.armHourAngle;
   FacePlateSecondTransformGroup.Children.Add(rotateTransformFacePlateMinute);
   FacePlateSecondTransformGroup.Children.Add(translateTransformFacePlateSecond);
   this.FaceSecond.RenderTransform = FacePlateSecondTransformGroup;
   return this.rotateTransform.Angle;
  }
 }
}

armsecond.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace silverlight_clock_singlearm
{
 public partial class ArmSecond : UserControl
 {
  private RotateTransform rotateTransform = new RotateTransform();
  public ArmSecond()
  {
   InitializeComponent();
   TranslateTransform translateTransform = new TranslateTransform();
   translateTransform.X = 2.2;
   translateTransform.Y = -40;
   this.RenderTransform = translateTransform;
  }
  internal double setAngle(DateTime _now)
  {
   int _seconds = _now.Second;
   int _milliseconds = _now.Millisecond;
   double secondFull = (double)_seconds * 6.00;
   double secondFraction = ((double)_milliseconds / 1000.00) * 6.00;
   this.rotateTransform.Angle =
    (secondFull + secondFraction) - MainPage.armMinuteAngle - MainPage.armHourAngle;
   this.CanvasArmSecond.RenderTransform = rotateTransform;
   return this.rotateTransform.Angle;
  }
 }
}
Enjoy!