Permalink
Browse files

Initial version of Ruby WiiMote whiteboard

  • Loading branch information...
wedesoft committed Oct 10, 2011
0 parents commit 1275e40ae459d2dfe5e362394acf5824693952d1
@@ -0,0 +1,4 @@
+.*.un~
+.*.swp
+whiteboard.tar.bz2
+
@@ -0,0 +1,36 @@
+SUFFICES = .cc .so .ui .qrc .rb
+
+CXX = g++
+RUBY = ruby
+RBUIC = rbuic4
+RBRCC = rbrcc
+
+RUBYINC = $(shell $(RUBY) -e "require 'mkmf'; puts Config::CONFIG.member?('rubyhdrdir') ? \"-I\#{Config::CONFIG['rubyhdrdir']} -I\#{Config::CONFIG['rubyhdrdir']}/\#{Config::CONFIG['arch']}\" : \"-I\#{Config::CONFIG['archdir']}\"")
+
+all: ui_mainwindow.rb qrc_whiteboard.rb x11test.so
+
+x11test.so: x11test.o
+ $(CXX) -shared -o $@ x11test.o -lXtst
+
+dist:
+ tar cjf whiteboard.tar.bz2 Makefile *.rb *.png *.ui *.qrc *.cc
+
+clean:
+ rm -f *.so *.o ui_*.rb qrc_*.rb
+
+qrc_whiteboard.rb: whiteboard.qrc exit.png configure.png connect.png disconnect.png \
+ whiteboard.png
+x11test.o: x11test.cc
+x11test.so: x11test.o
+
+ui_%.rb: %.ui
+ $(RBUIC) $< > $@
+
+qrc_%.rb: %.qrc
+ $(RBRCC) $< > $@
+
+.cc.o:
+ $(CXX) -c $< -o $@ -fPIC -O -DNDEBUG $(RUBYINC)
+
+-include $(wildcard .deps/*.P) :-)
+
@@ -0,0 +1,49 @@
+require 'Qt4'
+class CalibrateWidget < Qt::Widget
+ SIZE = 20
+ slots 'add_point(int,int)'
+ signals 'step_changed(int)'
+ signals 'finished()'
+ signals 'aborted()'
+ attr_reader :id
+ attr_reader :point_pairs
+ def initialize(parent = nil)
+ super parent
+ @id = 0
+ @point_pairs = []
+ end
+ def marker
+ [@id[0] == 1 ? width - SIZE : SIZE, @id[1] == 1 ? height - SIZE : SIZE]
+ end
+ def paintEvent(e)
+ super e
+ x, y = *marker
+ p = Qt::Painter.new self
+ p.translate x, y
+ pen = Qt::Pen.new Qt::Color.new(255, 0, 0)
+ pen.width = 3
+ p.pen = pen
+ p.drawLine -SIZE, 0, SIZE, 0
+ p.drawLine 0, -SIZE, 0, SIZE
+ p.drawEllipse -SIZE, -SIZE, 2 * SIZE + 1, 2 * SIZE + 1
+ p.end
+ end
+ def keyPressEvent(e)
+ if e.key == Qt::Key_Escape
+ emit aborted
+ close
+ end
+ end
+ def add_point(x, y)
+ @point_pairs += [[[x, y], marker]]
+ @id += 1
+ if @id < 4
+ emit step_changed(@id)
+ update
+ else
+ emit finished
+ close
+ end
+ end
+end
+
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN exit.png
Binary file not shown.
@@ -0,0 +1,39 @@
+require 'matrix'
+require 'linalg'
+include Linalg
+class Matrix
+ def to_dmatrix
+ DMatrix[*to_a]
+ end
+ def svd
+ to_dmatrix.svd.collect { |m| m.to_matrix }
+ end
+end
+class Vector
+ def reshape(w, h)
+ Matrix[*(0 ... h).collect { |i| to_a[i * w ... i.succ * w] }]
+ end
+end
+class DMatrix
+ def to_matrix
+ Matrix[*to_a]
+ end
+end
+class Homography
+ def initialize(*pairs)
+ constraints = []
+ pairs.each do |p,ps|
+ constraints.push [p[0].to_f, p[1].to_f, 1.0, 0.0, 0.0, 0.0,
+ -ps[0].to_f * p[0].to_f, -ps[0].to_f * p[1].to_f, -ps[0].to_f]
+ constraints.push [0.0, 0.0, 0.0, p[0].to_f, p[1].to_f, 1.0,
+ -ps[1].to_f * p[0].to_f, -ps[1].to_f * p[1].to_f, -ps[1].to_f]
+ end
+ @matrix = Matrix[*constraints].svd[2].row(8).reshape 3, 3
+ end
+ def transform(x, y)
+ p = Vector[x.to_f, y.to_f, 1.0]
+ ps = @matrix * p
+ [ps[0] / ps[2], ps[1] / ps[2]]
+ end
+end
+
@@ -0,0 +1,151 @@
+require 'Qt4'
+require 'ui_mainwindow'
+require 'calibratewidget'
+require 'homography'
+require 'cwiid'
+require 'x11test'
+class MainWindow < Qt::MainWindow
+ DELAY = 5000
+ slots 'wiimote(bool)'
+ slots 'calibrate()'
+ slots 'calib_step(int)'
+ slots 'calib_finish()'
+ slots 'calib_abort()'
+ slots 'tray(QSystemTrayIcon::ActivationReason)'
+ signals 'ir_clicked(int,int)'
+ signals 'ir_released()'
+ def initialize(parent = nil)
+ super parent
+ @ui = Ui::MainWindow.new
+ @ui.setupUi self
+ tray_menu = Qt::Menu.new self do |t|
+ t.addAction @ui.action_connect
+ t.addAction @ui.action_calibrate
+ t.addSeparator
+ t.addAction @ui.action_quit
+ end
+ @tray = Qt::SystemTrayIcon.new self
+ @tray.contextMenu = tray_menu
+ @tray.icon = windowIcon
+ connect @ui.action_connect, SIGNAL('toggled(bool)'), self, SLOT('wiimote(bool)')
+ connect @ui.action_calibrate, SIGNAL('triggered()'), self, SLOT('calibrate()')
+ connect @ui.action_quit, SIGNAL('triggered()'), $qApp, SLOT('quit()')
+ connect @tray, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'),
+ self, SLOT('tray(QSystemTrayIcon::ActivationReason)')
+ @tray.show
+ @wiimote = nil
+ @timer = 0
+ @state = false
+ @calibration = nil
+ @homography = nil
+ end
+ def wiimote(on)
+ begin
+ default = cursor
+ setCursor Qt::Cursor.new(Qt::WaitCursor)
+ if on
+ @wiimote = WiiMote.new
+ @wiimote.rpt_mode = WiiMote::RPT_BTN | WiiMote::RPT_IR
+ @ui.action_calibrate.enabled = true
+ @timer = startTimer 0
+ @tray.showMessage windowTitle, 'Established Bluetooth connection to Wii remote',
+ Qt::SystemTrayIcon::Information, DELAY
+ elsif @wiimote
+ @ui.action_calibrate.enabled = false
+ killTimer @timer
+ @homography = nil
+ @calibration = nil
+ @state = false
+ @timer = 0
+ @wiimote.close
+ @wiimote = nil
+ @tray.showMessage windowTitle, 'Dropped connection to Wii Remote',
+ Qt::SystemTrayIcon::Information, DELAY
+ end
+ setCursor default
+ rescue Exception => e
+ setCursor default
+ @tray.showMessage windowTitle, e.message, Qt::SystemTrayIcon::Critical, DELAY
+ @ui.action_connect.checked = false
+ end
+ end
+ def timerEvent(e)
+ led_next = Time.new.sec % 4
+ @wiimote.get_state
+ pos = @wiimote.ir.size > 0 ? @wiimote.ir.sort_by { |x,y,r| r }.last : nil
+ if pos and @homography
+ screen = @homography.transform pos[0], pos[1]
+ fake_motion_event screen[0].to_i, screen[1].to_i, 0
+ end
+ if pos.nil? == @state
+ @state = !@state
+ if @state
+ if @homography
+ fake_button_event 1, true, 0
+ else
+ emit ir_clicked(pos[0], pos[1])
+ end
+ else
+ if @homography
+ fake_button_event 1, false, 0
+ else
+ emit ir_released
+ end
+ end
+ end
+ end
+ def closeEvent(e)
+ if @tray.visible?
+ message = <<EOS
+The application will continue to run in the system tray.
+To terminate the program right-click on the tray icon and
+choose Quit in the context menu.
+EOS
+ @tray.showMessage windowTitle, message, Qt::SystemTrayIcon::Information, DELAY
+ hide
+ e.ignore
+ end
+ end
+ def calibrate
+ @homography = nil
+ @calibration = CalibrateWidget.new self
+ flags = Qt::Enum.new 0, 'Qt::WindowFlags'
+ flags |= Qt::DialogType
+ flags |= Qt::FramelessWindowHint
+ @calibration.windowFlags = flags
+ @calibration.cursor = Qt::Cursor.new Qt::BlankCursor
+ connect @ui.action_quit, SIGNAL('triggered()'), self, SLOT('close()')
+ connect self, SIGNAL('ir_clicked(int,int)'), @calibration, SLOT('add_point(int,int)')
+ connect @calibration, SIGNAL('step_changed(int)'), self, SLOT('calib_step(int)')
+ connect @calibration, SIGNAL('finished()'), self, SLOT('calib_finish()')
+ connect @calibration, SIGNAL('aborted()'), self, SLOT('calib_abort()')
+ @calibration.showFullScreen
+ @wiimote.led = 1 << @calibration.id
+ end
+ def calib_step(step)
+ @wiimote.led = 1 << step
+ end
+ def calib_finish
+ @wiimote.led = 0
+ disconnect self, nil, @calibration, nil
+ @homography = Homography.new *@calibration.point_pairs
+ @tray.showMessage windowTitle, 'Wii remote whiteboard was calibrated',
+ Qt::SystemTrayIcon::Information, DELAY
+ end
+ def calib_abort
+ disconnect self, nil, @calibration, nil
+ @wiimote.led = 0
+ @tray.showMessage windowTitle, 'Calibration was aborted',
+ Qt::SystemTrayIcon::Information, DELAY
+ end
+ def tray(reason)
+ if reason == Qt::SystemTrayIcon::Trigger
+ if visible?
+ hide
+ else
+ show
+ end
+ end
+ end
+end
+
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>White Board</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="whiteboard.qrc">
+ <normaloff>:/images/whiteboard.png</normaloff>:/images/whiteboard.png</iconset>
+ </property>
+ <widget class="QWidget" name="centralwidget"/>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menu_File">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="action_connect"/>
+ <addaction name="action_calibrate"/>
+ <addaction name="separator"/>
+ <addaction name="action_quit"/>
+ </widget>
+ <addaction name="menu_File"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <widget class="QToolBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="action_connect"/>
+ <addaction name="action_calibrate"/>
+ <addaction name="separator"/>
+ <addaction name="action_quit"/>
+ </widget>
+ <action name="action_quit">
+ <property name="icon">
+ <iconset resource="whiteboard.qrc">
+ <normaloff>:/images/exit.png</normaloff>:/images/exit.png</iconset>
+ </property>
+ <property name="text">
+ <string>&amp;Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="action_calibrate">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="whiteboard.qrc">
+ <normaloff>:/images/configure.png</normaloff>:/images/configure.png</iconset>
+ </property>
+ <property name="text">
+ <string>Ca&amp;librate</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+L</string>
+ </property>
+ </action>
+ <action name="action_connect">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="whiteboard.qrc">
+ <normaloff>:/images/wiimote.png</normaloff>:/images/wiimote.png</iconset>
+ </property>
+ <property name="text">
+ <string>Co&amp;nnect</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ </widget>
+ <resources>
+ <include location="whiteboard.qrc"/>
+ </resources>
+ <connections/>
+</ui>
Binary file not shown.
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/images">
+ <file>whiteboard.png</file>
+ <file>configure.png</file>
+ <file>exit.png</file>
+ <file>wiimote.png</file>
+ </qresource>
+</RCC>
Oops, something went wrong.

0 comments on commit 1275e40

Please sign in to comment.