Merge remote-tracking branch 'remotes/svn/master'

This commit is contained in:
2014-10-13 23:22:34 +01:00
37 changed files with 4595 additions and 0 deletions

74
build.xml Normal file
View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="wiigee-lib" default="default" basedir=".">
<description>Builds, tests, and runs the project JavaLibrary6.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar-with-manifest: JAR building (if you are using a manifest)
-do-jar-without-manifest: JAR building (if you are not using a manifest)
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="JavaLibrary6-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

View File

@@ -0,0 +1,10 @@
libs.junit_4.classpath=\
${base}/junit_4/junit-4.5.jar
libs.junit_4.javadoc=\
${base}/junit_4/junit-4.5-api.zip
libs.junit_4.src=\
${base}/junit_4/junit-4.5-src.jar
libs.junit.classpath=\
${base}/junit/junit-3.8.2.jar
libs.junit.javadoc=\
${base}/junit/junit-3.8.2-api.zip

721
nbproject/build-impl.xml Normal file
View File

@@ -0,0 +1,721 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
*** GENERATED FROM project.xml - DO NOT EDIT ***
*** EDIT ../build.xml INSTEAD ***
For the purpose of easier reading the script
is divided into following sections:
- initialization
- compilation
- jar
- execution
- debugging
- javadoc
- junit compilation
- junit execution
- junit debugging
- applet
- cleanup
-->
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="wiigee-lib-impl">
<fail message="Please build using Ant 1.7.1 or higher.">
<condition>
<not>
<antversion atleast="1.7.1"/>
</not>
</condition>
</fail>
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
<!--
======================
INITIALIZATION SECTION
======================
-->
<target name="-pre-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init" name="-init-private">
<property file="nbproject/private/config.properties"/>
<property file="nbproject/private/configs/${config}.properties"/>
<property file="nbproject/private/private.properties"/>
</target>
<target depends="-pre-init,-init-private" name="-init-libraries">
<property location="lib/nblibraries.properties" name="libraries.1.path"/>
<dirname file="${libraries.1.path}" property="libraries.1.dir.nativedirsep"/>
<pathconvert dirsep="/" property="libraries.1.dir">
<path path="${libraries.1.dir.nativedirsep}"/>
</pathconvert>
<basename file="${libraries.1.path}" property="libraries.1.basename" suffix=".properties"/>
<touch file="${libraries.1.dir}/${libraries.1.basename}-private.properties"/>
<loadproperties encoding="ISO-8859-1" srcfile="${libraries.1.dir}/${libraries.1.basename}-private.properties">
<filterchain>
<replacestring from="$${base}" to="${libraries.1.dir}"/>
<escapeunicode/>
</filterchain>
</loadproperties>
<loadproperties encoding="ISO-8859-1" srcfile="${libraries.1.path}">
<filterchain>
<replacestring from="$${base}" to="${libraries.1.dir}"/>
<escapeunicode/>
</filterchain>
</loadproperties>
</target>
<target depends="-pre-init,-init-private,-init-libraries" name="-init-user">
<property file="${user.properties.file}"/>
<!-- The two properties below are usually overridden -->
<!-- by the active platform. Just a fallback. -->
<property name="default.javac.source" value="1.4"/>
<property name="default.javac.target" value="1.4"/>
</target>
<target depends="-pre-init,-init-private,-init-libraries,-init-user" name="-init-project">
<property file="nbproject/configs/${config}.properties"/>
<property file="nbproject/project.properties"/>
</target>
<target depends="-pre-init,-init-private,-init-libraries,-init-user,-init-project,-init-macrodef-property" name="-do-init">
<available file="${manifest.file}" property="manifest.available"/>
<condition property="manifest.available+main.class">
<and>
<isset property="manifest.available"/>
<isset property="main.class"/>
<not>
<equals arg1="${main.class}" arg2="" trim="true"/>
</not>
</and>
</condition>
<condition property="manifest.available+main.class+mkdist.available">
<and>
<istrue value="${manifest.available+main.class}"/>
<isset property="libs.CopyLibs.classpath"/>
</and>
</condition>
<condition property="have.tests">
<or>
<available file="${test.src.dir}"/>
</or>
</condition>
<condition property="have.sources">
<or>
<available file="${src.dir}"/>
</or>
</condition>
<condition property="netbeans.home+have.tests">
<and>
<isset property="netbeans.home"/>
<isset property="have.tests"/>
</and>
</condition>
<condition property="no.javadoc.preview">
<and>
<isset property="javadoc.preview"/>
<isfalse value="${javadoc.preview}"/>
</and>
</condition>
<property name="run.jvmargs" value=""/>
<property name="javac.compilerargs" value=""/>
<property name="work.dir" value="${basedir}"/>
<condition property="no.deps">
<and>
<istrue value="${no.dependencies}"/>
</and>
</condition>
<property name="javac.debug" value="true"/>
<property name="javadoc.preview" value="true"/>
<property name="application.args" value=""/>
<property name="source.encoding" value="${file.encoding}"/>
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
<and>
<isset property="javadoc.encoding"/>
<not>
<equals arg1="${javadoc.encoding}" arg2=""/>
</not>
</and>
</condition>
<property name="javadoc.encoding.used" value="${source.encoding}"/>
<property name="includes" value="**"/>
<property name="excludes" value=""/>
<property name="do.depend" value="false"/>
<condition property="do.depend.true">
<istrue value="${do.depend}"/>
</condition>
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
<and>
<isset property="jaxws.endorsed.dir"/>
<available file="nbproject/jaxws-build.xml"/>
</and>
</condition>
</target>
<target name="-post-init">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="-pre-init,-init-private,-init-libraries,-init-user,-init-project,-do-init" name="-init-check">
<fail unless="src.dir">Must set src.dir</fail>
<fail unless="test.src.dir">Must set test.src.dir</fail>
<fail unless="build.dir">Must set build.dir</fail>
<fail unless="dist.dir">Must set dist.dir</fail>
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
<fail unless="dist.jar">Must set dist.jar</fail>
</target>
<target name="-init-macrodef-property">
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<property name="@{name}" value="${@{value}}"/>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-javac">
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="${javac.debug}" name="debug"/>
<attribute default="${empty.dir}" name="sourcepath"/>
<attribute default="${empty.dir}" name="gensrcdir"/>
<element name="customize" optional="true"/>
<sequential>
<property location="${build.dir}/empty" name="empty.dir"/>
<mkdir dir="${empty.dir}"/>
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
<src>
<dirset dir="@{gensrcdir}" erroronmissingdir="false">
<include name="*"/>
</dirset>
</src>
<classpath>
<path path="@{classpath}"/>
</classpath>
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
<customize/>
</javac>
</sequential>
</macrodef>
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${src.dir}" name="srcdir"/>
<attribute default="${build.classes.dir}" name="destdir"/>
<attribute default="${javac.classpath}" name="classpath"/>
<sequential>
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</depend>
</sequential>
</macrodef>
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${build.classes.dir}" name="destdir"/>
<sequential>
<fail unless="javac.includes">Must set javac.includes</fail>
<pathconvert pathsep="," property="javac.includes.binary">
<path>
<filelist dir="@{destdir}" files="${javac.includes}"/>
</path>
<globmapper from="*.java" to="*.class"/>
</pathconvert>
<delete>
<files includes="${javac.includes.binary}"/>
</delete>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-junit">
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${includes}" name="includes"/>
<attribute default="${excludes}" name="excludes"/>
<attribute default="**" name="testincludes"/>
<sequential>
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
<batchtest todir="${build.test.results.dir}">
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
<filename name="@{testincludes}"/>
</fileset>
</batchtest>
<classpath>
<path path="${run.test.classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<formatter type="brief" usefile="false"/>
<formatter type="xml"/>
<jvmarg line="${run.jvmargs}"/>
</junit>
</sequential>
</macrodef>
</target>
<target depends="-init-debug-args" name="-init-macrodef-nbjpda">
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="name"/>
<attribute default="${debug.classpath}" name="classpath"/>
<attribute default="" name="stopclassname"/>
<sequential>
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
<classpath>
<path path="@{classpath}"/>
</classpath>
</nbjpdastart>
</sequential>
</macrodef>
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${build.classes.dir}" name="dir"/>
<sequential>
<nbjpdareload>
<fileset dir="@{dir}" includes="${fix.classes}">
<include name="${fix.includes}*.class"/>
</fileset>
</nbjpdareload>
</sequential>
</macrodef>
</target>
<target name="-init-debug-args">
<property name="version-output" value="java version &quot;${ant.java.version}"/>
<condition property="have-jdk-older-than-1.4">
<or>
<contains string="${version-output}" substring="java version &quot;1.0"/>
<contains string="${version-output}" substring="java version &quot;1.1"/>
<contains string="${version-output}" substring="java version &quot;1.2"/>
<contains string="${version-output}" substring="java version &quot;1.3"/>
</or>
</condition>
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
<istrue value="${have-jdk-older-than-1.4}"/>
</condition>
<condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
<os family="windows"/>
</condition>
<condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
<isset property="debug.transport"/>
</condition>
</target>
<target depends="-init-debug-args" name="-init-macrodef-debug">
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
<attribute default="${main.class}" name="classname"/>
<attribute default="${debug.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg line="${debug-args-line}"/>
<jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-macrodef-java">
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
<attribute default="${main.class}" name="classname"/>
<attribute default="${run.classpath}" name="classpath"/>
<element name="customize" optional="true"/>
<sequential>
<java classname="@{classname}" dir="${work.dir}" fork="true">
<jvmarg value="-Dfile.encoding=${source.encoding}"/>
<redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
<jvmarg line="${run.jvmargs}"/>
<classpath>
<path path="@{classpath}"/>
</classpath>
<syspropertyset>
<propertyref prefix="run-sys-prop."/>
<mapper from="run-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<customize/>
</java>
</sequential>
</macrodef>
</target>
<target name="-init-presetdef-jar">
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
<jar compress="${jar.compress}" jarfile="${dist.jar}">
<j2seproject1:fileset dir="${build.classes.dir}"/>
</jar>
</presetdef>
</target>
<target depends="-pre-init,-init-private,-init-libraries,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
<!--
===================
COMPILATION SECTION
===================
-->
<target depends="init" name="deps-jar" unless="no.deps"/>
<target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
<target depends="init" name="-check-automatic-build">
<available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
</target>
<target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
<antcall target="clean"/>
</target>
<target depends="init,deps-jar" name="-pre-pre-compile">
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="-pre-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-depend">
<pathconvert property="build.generated.subdirs">
<dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="*"/>
</dirset>
</pathconvert>
<j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
</target>
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
<copy todir="${build.classes.dir}">
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
<target name="-pre-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile/>
<j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
</target>
<target name="-post-compile-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
<!--
====================
JAR BUILDING SECTION
====================
-->
<target depends="init" name="-pre-pre-jar">
<dirname file="${dist.jar}" property="dist.jar.dir"/>
<mkdir dir="${dist.jar.dir}"/>
</target>
<target name="-pre-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
<j2seproject1:jar/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
<j2seproject1:jar manifest="${manifest.file}"/>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
<j2seproject1:jar manifest="${manifest.file}">
<j2seproject1:manifest>
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
</j2seproject1:manifest>
</j2seproject1:jar>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<pathconvert property="run.classpath.with.dist.jar">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
</pathconvert>
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</copylibs>
<echo>To run this application from the command line without Ant, try:</echo>
<property location="${dist.jar}" name="dist.jar.resolved"/>
<echo>java -jar "${dist.jar.resolved}"</echo>
</target>
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="libs.CopyLibs.classpath" name="-do-jar-with-libraries-without-manifest" unless="manifest.available+main.class">
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
<pathconvert property="run.classpath.without.build.classes.dir">
<path path="${run.classpath}"/>
<map from="${build.classes.dir.resolved}" to=""/>
</pathconvert>
<pathconvert pathsep=" " property="jar.classpath">
<path path="${run.classpath.without.build.classes.dir}"/>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="lib/*"/>
</chainedmapper>
</pathconvert>
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
<fileset dir="${build.classes.dir}"/>
</copylibs>
</target>
<target name="-post-jar">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-do-jar-with-libraries-without-manifest,-post-jar" description="Build JAR." name="jar"/>
<!--
=================
EXECUTION SECTION
=================
-->
<target depends="init,compile" description="Run a main class." name="run">
<j2seproject1:java>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject1:java>
</target>
<target name="-do-not-recompile">
<property name="javac.includes.binary" value=""/>
</target>
<target depends="init,-do-not-recompile,compile-single" name="run-single">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single" name="run-test-with-main">
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
<j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
</target>
<!--
=================
DEBUGGING SECTION
=================
-->
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
<j2seproject1:nbjpdastart name="${debug.class}"/>
</target>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
</target>
<target depends="init,compile" name="-debug-start-debuggee">
<j2seproject3:debug>
<customize>
<arg line="${application.args}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
</target>
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
<target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
<j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
<target depends="init" name="-pre-debug-fix">
<fail unless="fix.includes">Must set fix.includes</fail>
<property name="javac.includes" value="${fix.includes}.java"/>
</target>
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
<j2seproject1:nbjpdareload/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
<!--
===============
JAVADOC SECTION
===============
-->
<target depends="init" name="-javadoc-build">
<mkdir dir="${dist.javadoc.dir}"/>
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
<classpath>
<path path="${javac.classpath}"/>
</classpath>
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
<filename name="**/*.java"/>
</fileset>
<fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
<include name="**/*.java"/>
</fileset>
</javadoc>
</target>
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
</target>
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
<!--
=========================
JUNIT COMPILATION SECTION
=========================
-->
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
<mkdir dir="${build.test.classes.dir}"/>
</target>
<target name="-pre-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target if="do.depend.true" name="-compile-test-depend">
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
<target name="-pre-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
<copy todir="${build.test.classes.dir}">
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
</copy>
</target>
<target name="-post-compile-test-single">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
<!--
=======================
JUNIT EXECUTION SECTION
=======================
-->
<target depends="init" if="have.tests" name="-pre-test-run">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
<j2seproject3:junit testincludes="**/*Test.java"/>
</target>
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init" if="have.tests" name="test-report"/>
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
<target depends="init" if="have.tests" name="-pre-test-run-single">
<mkdir dir="${build.test.results.dir}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
<j2seproject3:junit excludes="" includes="${test.includes}"/>
</target>
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
<fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
<!--
=======================
JUNIT DEBUGGING SECTION
=======================
-->
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
<delete file="${test.report.file}"/>
<mkdir dir="${build.test.results.dir}"/>
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
<customize>
<syspropertyset>
<propertyref prefix="test-sys-prop."/>
<mapper from="test-sys-prop.*" to="*" type="glob"/>
</syspropertyset>
<arg value="${test.class}"/>
<arg value="showoutput=true"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
</target>
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
</target>
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
<!--
=========================
APPLET EXECUTION SECTION
=========================
-->
<target depends="init,compile-single" name="run-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject1:java classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject1:java>
</target>
<!--
=========================
APPLET DEBUGGING SECTION
=========================
-->
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
<j2seproject3:debug classname="sun.applet.AppletViewer">
<customize>
<arg value="${applet.url}"/>
</customize>
</j2seproject3:debug>
</target>
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
<!--
===============
CLEANUP SECTION
===============
-->
<target depends="init" name="deps-clean" unless="no.deps"/>
<target depends="init" name="-do-clean">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="-post-clean">
<!-- Empty placeholder for easier customization. -->
<!-- You can override this target in the ../build.xml file. -->
</target>
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
</project>

View File

@@ -0,0 +1,8 @@
build.xml.data.CRC32=a8056d46
build.xml.script.CRC32=3a7a628a
build.xml.stylesheet.CRC32=958a1d3e
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=afb4810b
nbproject/build-impl.xml.script.CRC32=7668b6e9
nbproject/build-impl.xml.stylesheet.CRC32=5c621a33@1.26.1.45

View File

@@ -0,0 +1,70 @@
application.title=wiigee-lib
application.vendor=bepo
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/wiigee-lib.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
includes=**
jar.compress=false
javac.classpath=
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.source=1.5
javac.target=1.5
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}:\
${libs.junit.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
jnlp.codebase.type=local
jnlp.codebase.url=file:/Users/bepo/develop/java/wiigee/trunk/wiigee-lib/dist
jnlp.descriptor=application
jnlp.enabled=false
jnlp.offline-allowed=false
jnlp.signed=false
meta.inf.dir=${src.dir}/META-INF
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
# or test-sys-prop.name=value to set system properties for unit tests):
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=src
test.src.dir=test

19
nbproject/project.xml Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>wiigee-lib</name>
<minimum-ant-version>1.6.5</minimum-ant-version>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots>
<root id="test.src.dir"/>
</test-roots>
</data>
<libraries xmlns="http://www.netbeans.org/ns/ant-project-libraries/1">
<definitions>lib/nblibraries.properties</definitions>
</libraries>
</configuration>
</project>

View File

@@ -0,0 +1,46 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.control;
import org.wiigee.util.Log;
/**
* The mother of all classes. :-) It's just used as parent class
* to print version information and later on maybe dynamic configuring
* of the whole wiimote system... detecting plugins and devices automatically
* maybe. :)
*
* @author Benjamin 'BePo' Poppinga
*/
public class Wiigee {
protected static String version = "1.5.5 alpha";
protected static String releasedate = "20090714";
protected Wiigee() {
Log.write("This is wiigee version "+version+" ("+releasedate+")");
}
}

View File

@@ -0,0 +1,234 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.device;
import java.io.IOException;
import java.util.Vector;
import org.wiigee.logic.*;
import org.wiigee.event.*;
import org.wiigee.filter.*;
/**
* Abstract representation of a device with very basic functionalities. This
* class should be derived from, if anybody plans to add a new class of devices,
* like Wiimote or AndroidDevice does. This class mainly consist of filter
* management, recognition control and core event control.
*
* @author Benjamin 'BePo' Poppinga
*/
public class Device {
// Fixed number values.
public static final int MOTION = 0;
// Buttons for action coordination
protected int recognitionbutton;
protected int trainbutton;
protected int closegesturebutton;
// Functional
protected boolean accelerationEnabled;
// Filters, can filter the data stream
protected Vector<Filter> accfilters = new Vector<Filter>();
// Listeners, receive generated events
protected Vector<AccelerationListener> accelerationlistener = new Vector<AccelerationListener>();
protected Vector<ButtonListener> buttonlistener = new Vector<ButtonListener>();
// Processing unit to analyze the data
protected ProcessingUnit processingunit = new TriggeredProcessingUnit();
public Device(boolean autofiltering) {
if (autofiltering) {
this.addAccelerationFilter(new IdleStateFilter());
this.addAccelerationFilter(new MotionDetectFilter(this));
this.addAccelerationFilter(new DirectionalEquivalenceFilter());
}
this.addAccelerationListener(this.processingunit);
this.addButtonListener(this.processingunit);
}
/**
* Adds a Filter for processing the acceleration values.
* @param filter The Filter instance.
*/
public void addAccelerationFilter(Filter filter) {
this.accfilters.add(filter);
}
/**
* Resets all the accfilters, which are resetable.
* Sometimes they have to be resettet if a new gesture starts.
*/
public void resetAccelerationFilters() {
for (int i = 0; i < this.accfilters.size(); i++) {
this.accfilters.elementAt(i).reset();
}
}
/**
* Adds an AccelerationListener to the Device. Everytime an acceleration
* on the Device is performed the AccelerationListener would receive
* an event of this action.
*
* @param listener The Listener.
*/
public void addAccelerationListener(AccelerationListener listener) {
this.accelerationlistener.add(listener);
}
/**
* Adds a ButtonListener to the Device. Everytime a Button has been
* pressed or released, the Listener would be notified about this via
* the corresponding Events.
*
* @param listener The Listener.
*/
public void addButtonListener(ButtonListener listener) {
this.buttonlistener.add(listener);
}
/**
* Adds a GestureListener to the Device. Everytime a gesture
* is performed the GestureListener would receive an event of
* this gesture.
*
* @param listener The Listener.
*/
public void addGestureListener(GestureListener listener) {
this.processingunit.addGestureListener(listener);
}
public int getRecognitionButton() {
return this.recognitionbutton;
}
public void setRecognitionButton(int b) {
this.recognitionbutton = b;
}
public int getTrainButton() {
return this.trainbutton;
}
public void setTrainButton(int b) {
this.trainbutton = b;
}
public int getCloseGestureButton() {
return this.closegesturebutton;
}
public void setCloseGestureButton(int b) {
this.closegesturebutton = b;
}
public ProcessingUnit getProcessingUnit() {
return this.processingunit;
}
public void setAccelerationEnabled(boolean enabled) throws IOException {
this.accelerationEnabled = enabled;
}
public void loadGesture(String filename) {
this.processingunit.loadGesture(filename);
}
public void saveGesture(int id, String filename) {
this.processingunit.saveGesture(id, filename);
}
// ###### Event-Methoden
/** Fires an acceleration event.
* @param vector Consists of three values:
* acceleration on X, Y and Z axis.
*/
public void fireAccelerationEvent(double[] vector) {
for (int i = 0; i < this.accfilters.size(); i++) {
vector = this.accfilters.get(i).filter(vector);
// cannot return here if null, because of time-dependent accfilters
}
// don't need to create an event if filtered away
if (vector != null) {
// calculate the absolute value for the accelerationevent
double absvalue = Math.sqrt((vector[0] * vector[0]) +
(vector[1] * vector[1]) + (vector[2] * vector[2]));
AccelerationEvent w = new AccelerationEvent(this,
vector[0], vector[1], vector[2], absvalue);
for (int i = 0; i < this.accelerationlistener.size(); i++) {
this.accelerationlistener.get(i).accelerationReceived(w);
}
}
} // fireaccelerationevent
/** Fires a button pressed event.
* @param button
* Integer value of the pressed button.
*/
public void fireButtonPressedEvent(int button) {
ButtonPressedEvent w = new ButtonPressedEvent(this, button);
for (int i = 0; i < this.buttonlistener.size(); i++) {
this.buttonlistener.get(i).buttonPressReceived(w);
}
if (w.isRecognitionInitEvent() || w.isTrainInitEvent()) {
this.resetAccelerationFilters();
}
}
/** Fires a button released event.
*/
public void fireButtonReleasedEvent(int button) {
ButtonReleasedEvent w = new ButtonReleasedEvent(this, button);
for (int i = 0; i < this.buttonlistener.size(); i++) {
this.buttonlistener.get(i).buttonReleaseReceived(w);
}
}
/**
* Fires a motion start event.
*/
public void fireMotionStartEvent() {
MotionStartEvent w = new MotionStartEvent(this);
for (int i = 0; i < this.accelerationlistener.size(); i++) {
this.accelerationlistener.get(i).motionStartReceived(w);
}
}
/**
* Fires a motion stop event.
*/
public void fireMotionStopEvent() {
MotionStopEvent w = new MotionStopEvent(this);
for (int i = 0; i < this.accelerationlistener.size(); i++) {
this.accelerationlistener.get(i).motionStopReceived(w);
}
}
}

View File

@@ -0,0 +1,79 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventObject;
import org.wiigee.device.*;
/**
* This Event would be generated if an acceleration has been detected.
* It contains information about the force applied to the device in each
* direction (x, y, z). Further it contains the absolute value of this
* vector and the source which generated this event (Device).
*
* @author Benjamin 'BePo' Poppinga
*
*/
public class AccelerationEvent extends EventObject {
double X, Y, Z;
double absvalue;
/**
* Create an AccelerationEvent with a specific source,
* all the three acceleration values and the calculated absolute
* value.
*
* @param source The source which has been accelerated (Wiimote).
* @param X The value of acceleration in the x direction.
* @param Y The value of acceleration in the y direction.
* @param Z The value of acceleration in the z direction.
* @param absvalue The absolute value of this acceleration vector.
*/
public AccelerationEvent(Device source, double X, double Y, double Z, double absvalue) {
super(source);
this.X=X;
this.Y=Y;
this.Z=Z;
this.absvalue=absvalue;
}
public double getX() {
return X;
}
public double getY() {
return Y;
}
public double getZ() {
return Z;
}
public double getAbsValue() {
return absvalue;
}
}

View File

@@ -0,0 +1,65 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventListener;
/**
* This interface has to be implemented if the application should react
* to pure acceleration data. This could be useful if you want to e.g.
* graphically display the acceleration data in your application.
*
* @author Benjamin 'BePo' Poppinga
*/
public interface AccelerationListener extends EventListener {
/**
* This method would be called if a Device source has been accelerated.
*
* @param event The acceleration representation as an event.
*/
public abstract void accelerationReceived(AccelerationEvent event);
/**
* This method would be called if a Device is in idle state and then a
* motion starts or if a Device is in motion and then the motion stops and
* the Device is in idle state.
*
* @param event This is the event which contains if the Wiimote is now
* in motion or not.
*/
public abstract void motionStartReceived(MotionStartEvent event);
/**
* This method would be called if a Device is in motion and then the motion
* stops and the Device is in idle state.
*
* @param event This is the event which contains if the Device is now
* in motion or not.
*/
public abstract void motionStopReceived(MotionStopEvent event);
}

View File

@@ -0,0 +1,84 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventObject;
import org.wiigee.device.Device;
/**
* An ActionStartEvent is an Event where other different events can
* be derived from, if they can be considered as an event actually starting
* a process like e.g. Training, Recognition, ...
*
* @author Benjamin 'BePo' Poppinga
*/
public class ActionStartEvent extends EventObject {
protected boolean trainbutton;
protected boolean recognitionbutton;
protected boolean closegesturebutton;
public ActionStartEvent(Device source) {
super(source);
}
/**
* Is true if this button press has been done by the
* individual defined RecognitionButton which has to be
* set during initialization of a Wiimote.
*
* @return Is this button press initiated by the recognition button.
* @see device.Wiimote#setRecognitionButton(int) setRecognitionButton()
*/
public boolean isRecognitionInitEvent() {
return this.recognitionbutton;
}
/**
* Is true if this button press has been done by the
* individual defined TrainButton which has to be
* set during initialization of a Wiimote.
*
* @return Is this button pres initiated by the training button.
* @see device.Wiimote#setTrainButton(int) setTrainButton()
*/
public boolean isTrainInitEvent() {
return this.trainbutton;
}
/**
* Is true if this button press has been done by the
* individual defined CloseGestureButton which has to be
* set during initialization of a Wiimote.
*
* @return Is this button press initiated by the close gesture button.
* @see device.Wiimote#setCloseGestureButton(int) setCloseGestureButton()
*/
public boolean isCloseGestureInitEvent() {
return this.closegesturebutton;
}
}

View File

@@ -0,0 +1,43 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventObject;
import org.wiigee.device.Device;
/**
* An ActionStopEvent is an Event where other different events can
* be derived from, if they can be considered as an event actually stopping
* a process like e.g. Training, Recognition, ...
*
* @author Benjamin 'BePo' Poppinga
*/
public class ActionStopEvent extends EventObject {
public ActionStopEvent(Device source) {
super(source);
}
}

View File

@@ -0,0 +1,54 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventListener;
/**
* This interface has to be implemented if the application should react
* to button press/releases.
*
* @author Benjamin 'BePo' Poppinga
*/
public interface ButtonListener extends EventListener {
/**
* This method would be called if a Device button has been pressed.
*
* @param event The button representation as an event.
*/
public abstract void buttonPressReceived(ButtonPressedEvent event);
/**
* This method would be called if a Device button has been released.
*
* @param event This is actually a meta-event NOT containing which button
* has been released.
*/
public abstract void buttonReleaseReceived(ButtonReleasedEvent event);
}

View File

@@ -0,0 +1,80 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import org.wiigee.device.*;
/**
*
* This Event would be generated if a button on a wiimote has been
* pressed by user. It contains the source (wiimote) and an integer
* representation of which button has been pressed. Please note that
* there exist enumeration constants in the class, so you don't
* have to use this integer values directly.
*
* @author Benjamin 'BePo' Poppinga
*/
public class ButtonPressedEvent extends ActionStartEvent {
// Fixed number values.
public static final int BUTTON_2 = 1;
public static final int BUTTON_1 = 2;
public static final int BUTTON_B = 3;
public static final int BUTTON_A = 4;
public static final int BUTTON_MINUS = 5;
public static final int BUTTON_HOME = 8;
public static final int BUTTON_LEFT = 9;
public static final int BUTTON_RIGHT = 10;
public static final int BUTTON_DOWN = 11;
public static final int BUTTON_UP = 12;
public static final int BUTTON_PLUS = 13;
int button;
/**
* Create a WiimoteButtonPressedEvent with the Wiimote source whose
* Button has been pressed and the integer representation of the button.
*
* @param source
* @param button
*/
public ButtonPressedEvent(Device source, int button) {
super(source);
this.button=button;
if(source.getRecognitionButton()==button) {
this.recognitionbutton=true;
} else if(source.getTrainButton()==button) {
this.trainbutton=true;
} else if(source.getCloseGestureButton()==button) {
this.closegesturebutton=true;
}
}
public int getButton() {
return this.button;
}
}

View File

@@ -0,0 +1,49 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import org.wiigee.device.*;
/**
*
* This event would be generated if a button was released.
* contains: source (wiimote).
*
* @author Benjamin 'BePo' Poppinga
*/
public class ButtonReleasedEvent extends ActionStopEvent {
int button;
public ButtonReleasedEvent(Device source, int button) {
super(source);
this.button = button;
}
public int getButton() {
return this.button;
}
}

View File

@@ -0,0 +1,71 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import org.wiigee.logic.ProcessingUnit;
/**
* This event would be generated if a gesture has been detected.
* It contains information about the gesture "name" or type,
* the accelerationstreamanalyzer which generated the event (source)
* and the probability calculated from the bayes classifier.
*
* @author Benjamin 'BePo' Poppinga
*/
public class GestureEvent {
int id;
boolean valid;
double probability;
ProcessingUnit analyzer;
/** Create a GestureEvent
*
* @param source The Source, which detected the gesture.
* @param id A gesture ID for identifying a gesture.
* @param probability The Bayes-Classifier calculated probability.
*/
public GestureEvent(ProcessingUnit source, boolean valid, int id, double probability) {
this.analyzer = source;
this.valid = valid;
this.id = id;
this.probability = probability;
}
public int getId() {
return this.id;
}
public boolean isValid() {
return this.valid;
}
public double getProbability() {
return this.probability;
}
public ProcessingUnit getSource() {
return this.analyzer;
}
}

View File

@@ -0,0 +1,47 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import java.util.EventListener;
/**
*
* This is the GestureListener interface which has to be implemented
* by any application which should receive recognized gestures.
*
* @author Benjamin 'BePo' Poppinga
*
*/
public interface GestureListener extends EventListener {
/**
* This method would be called if a gesture has been recognized.
*
* @param event The GestureEvent containing information about
* the recognized gesture.
*/
public abstract void gestureReceived(GestureEvent event);
}

View File

@@ -0,0 +1,63 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import org.wiigee.device.Device;
/**
* This Event gets fired, if the Device starts to move.
*
* @author Benjamin 'BePo' Poppinga
*/
public class MotionStartEvent extends ActionStartEvent {
public MotionStartEvent(Device source) {
super(source);
if(source.getRecognitionButton()==Device.MOTION) {
this.recognitionbutton=true;
} else if(source.getTrainButton()==Device.MOTION) {
this.trainbutton=true;
} else if(source.getCloseGestureButton()==Device.MOTION) {
this.closegesturebutton=true;
}
}
@Override
public boolean isTrainInitEvent() {
return this.trainbutton;
}
@Override
public boolean isCloseGestureInitEvent() {
return this.closegesturebutton;
}
@Override
public boolean isRecognitionInitEvent() {
return this.recognitionbutton;
}
}

View File

@@ -0,0 +1,42 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.event;
import org.wiigee.device.Device;
/**
*
* This event would be generated if a motion stops.
* contains: source.
*
* @author Benjamin 'BePo' Poppinga
*/
public class MotionStopEvent extends ActionStopEvent {
public MotionStopEvent(Device source) {
super(source);
}
}

View File

@@ -0,0 +1,70 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
/**
* This filter removes a vector, if it doesn't differ enough from
* the previously retrieved filter.
*
* @author Benjamin 'BePo' Poppinga
*/
public class DirectionalEquivalenceFilter extends Filter {
private double sensivity;
private double[] reference;
public DirectionalEquivalenceFilter() {
super();
this.reset();
}
public void reset() {
this.sensivity=0.2;
this.reference = new double[] {0.0, 0.0, 0.0};
}
public double[] filterAlgorithm(double[] vector) {
if(vector[0]<reference[0]-this.sensivity ||
vector[0]>reference[0]+this.sensivity ||
vector[1]<reference[1]-this.sensivity ||
vector[1]>reference[1]+this.sensivity ||
vector[2]<reference[2]-this.sensivity ||
vector[2]>reference[2]+this.sensivity) {
this.reference=vector;
return vector;
} else {
return null;
}
}
public void setSensivity(double sensivity) {
this.sensivity=sensivity;
}
public double getSensivity() {
return this.sensivity;
}
}

View File

@@ -0,0 +1,62 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
/**
* Abstract class to give a definition for a general filter.
*
* @author Benjamin 'BePo' Poppinga
*/
public abstract class Filter {
/***
* The actual called method to filter anything. It checks if the vector is
* already set to NULL by another filter and won't process it anymore. If it's
* not NULL it would be forwarded to the actual implemented method - filterAlgorithm().
* @param vector The acceleration vector, encoding: 0/x, 1/y, 2/z
* @return a new, filtered acceleration vector, encoded the same way
*/
public double[] filter(double[] vector) {
if(vector==null) {
return null;
} else {
return filterAlgorithm(vector);
}
}
/***
* A filter receives a triple of acceleration values within the variable 'vector'.
* It's encoded as vector[0]=x, vector[1]=y, vector[2]=z. This is not an object since the
* processing of the filter should be really fast, since every acceleration of the wiimote
* passes the filter.
* @param vector
* @param absvalue
* @return
*/
abstract public double[] filterAlgorithm(double[] vector);
abstract public void reset();
}

View File

@@ -0,0 +1,71 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
/**
*
* This filter removes every acceleration that happens slowly or
* steadily (like e.g. gravity). Remember: It _passes_ acceleration
* with a big variety.
*
* @author Benjamin 'BePo' Poppinga
*/
public class HighPassFilter extends Filter {
private double factor;
private double[] prevAcc;
public HighPassFilter() {
super();
this.factor = 0.1;
this.reset();
}
public HighPassFilter(double factor) {
super();
this.factor = factor;
this.reset();
}
@Override
public void reset() {
this.prevAcc = new double[] {0.0, 0.0, 0.0};
}
@Override
public double[] filterAlgorithm(double[] vector) {
double[] retVal = new double[3];
prevAcc[0] = vector[0] * this.factor + this.prevAcc[0] * (1.0 - this.factor);
prevAcc[1] = vector[1] * this.factor + this.prevAcc[1] * (1.0 - this.factor);
prevAcc[2] = vector[2] * this.factor + this.prevAcc[2] * (1.0 - this.factor);
retVal[0] = vector[0] - prevAcc[0];
retVal[1] = vector[1] - prevAcc[1];
retVal[2] = vector[2] - prevAcc[2];
return retVal;
}
}

View File

@@ -0,0 +1,86 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
/**
* Filters if the wiimote is not moved in any way. Be careful in using
* this filter together with a HighPassFilter.
*
* @author Benjamin 'BePo' Poppinga
*/
public class IdleStateFilter extends Filter {
private double sensivity;
/**
* Since an acceleration sensor usually provides information even
* if it doesn't move, this filter removes the data if it's in the
* idle state.
*/
public IdleStateFilter() {
super();
this.sensivity = 0.1;
}
@Override
public void reset() {
// not needed
}
@Override
public double[] filterAlgorithm(double[] vector) {
// calculate values needed for filtering:
// absolute value
double absvalue = Math.sqrt((vector[0]*vector[0])+
(vector[1]*vector[1])+(vector[2]*vector[2]));
// filter formulaes and return values
if(absvalue > 1+this.sensivity ||
absvalue < 1-this.sensivity) {
return vector;
} else {
return null;
}
}
/**
* Defines the absolute value when the wiimote should react to acceleration.
* This is a parameter for the first of the two filters: idle state
* filter. For example: sensivity=0.2 makes the wiimote react to acceleration
* where the absolute value is equal or greater than 1.2g. The default value 0.1
* should work well. Only change if you are sure what you're doing.
*
* @param sensivity
* acceleration data values smaller than this value wouldn't be detected.
*/
public void setSensivity(double sensivity) {
this.sensivity = sensivity;
}
public double getSensivity() {
return this.sensivity;
}
}

View File

@@ -0,0 +1,67 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
/**
*
* This filter removes every acceleration that happens fast or
* suddenly (like e.g. a short hit). Remember: It _passes_ acceleration
* with a slight variety.
*
* @author Benjamin 'BePo' Poppinga
*/
public class LowPassFilter extends Filter {
private double factor;
private double[] prevAcc;
public LowPassFilter() {
super();
this.factor = 0.01;
this.reset();
}
public LowPassFilter(double factor) {
super();
this.factor = factor;
this.reset();
}
@Override
public void reset() {
this.prevAcc = new double[] {0.0, 0.0, 0.0};
}
@Override
public double[] filterAlgorithm(double[] vector) {
double[] retVal = new double[3];
retVal[0] = vector[0] * this.factor + this.prevAcc[0] * (1.0 - this.factor);
retVal[1] = vector[1] * this.factor + this.prevAcc[1] * (1.0 - this.factor);
retVal[2] = vector[2] * this.factor + this.prevAcc[2] * (1.0 - this.factor);
this.prevAcc = retVal;
return retVal;
}
}

View File

@@ -0,0 +1,102 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.filter;
import org.wiigee.device.Device;
/**
* This filter uses time to determine if the wiimote actually is in motion
* or not. This filter only works together with the IdleStateFilter.
*
* @author Benjamin 'BePo' Poppinga
*/
public class MotionDetectFilter extends Filter {
private int motionchangetime;
private boolean nowinmotion;
private long motionstartstamp;
private Device device;
/***
* Detects wheather the wiimote receives acceleration or not and
* raises an event, if the device starts or stops. This is actual a
* null filter, not manipulating anything. But looks pretty good in
* this datatype since it could be removed easily.
*
* @param wiimote The Wiimote object which is controlled by the filter.
*/
public MotionDetectFilter(Device device) {
super();
this.device=device;
this.reset();
}
public void reset() {
this.motionstartstamp=System.currentTimeMillis();
this.nowinmotion=false;
this.motionchangetime=190;
}
@Override
public double[] filter(double[] vector) {
if(this.nowinmotion &&
(System.currentTimeMillis()-this.motionstartstamp)>=
this.motionchangetime) {
this.nowinmotion=false;
this.device.fireMotionStopEvent();
} // fi
return filterAlgorithm(vector);
}
public double[] filterAlgorithm(double[] vector) {
if(vector!=null) {
this.motionstartstamp=System.currentTimeMillis();
if(!this.nowinmotion) {
this.nowinmotion=true;
this.motionstartstamp=System.currentTimeMillis();
this.device.fireMotionStartEvent();
}
}
return vector;
}
/**
* Defines the time the wiimote has to be in idle state before a new motion change
* event appears. The default value 500ms should work well, only change it if you are sure
* about what you're doing.
* @param time Time in ms
*/
public void setMotionChangeTime(int time) {
this.motionchangetime=time;
}
public int getMotionChangeTime() {
return this.motionchangetime;
}
}

View File

@@ -0,0 +1,109 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.util.Vector;
public class Classifier {
private Vector<GestureModel> gesturemodel; // each gesturetype got its own
// gesturemodel in this vector
private double lastprob;
public Classifier() {
this.gesturemodel=new Vector<GestureModel>();
this.lastprob=0.0;
}
/**
* This method recognize a specific gesture, given to the procedure.
* For classification a bayes classification algorithm is used.
*
* @param g gesture to classify
*/
public int classifyGesture(Gesture g) {
//Log.write("Recognizing gesture...");
// Wert im Nenner berechnen, nach Bayes
double sum = 0;
for(int i=0; i<this.gesturemodel.size(); i++) {
sum+=this.gesturemodel.elementAt(i).getDefaultProbability()*
this.gesturemodel.elementAt(i).matches(g);
}
int recognized = -1; // which gesture has been recognized
double recogprob = Integer.MIN_VALUE; // probability of this gesture
double probgesture = 0; // temporal value for bayes algorithm
double probmodel = 0; // temporal value for bayes algorithm
for(int i=0; i<this.gesturemodel.size(); i++) {
//this.gesturemodel.elementAt(i).print(); // Debug
double tmpgesture = this.gesturemodel.elementAt(i).matches(g);
double tmpmodel = this.gesturemodel.elementAt(i).getDefaultProbability();
if(((tmpmodel*tmpgesture)/sum)>recogprob) {
probgesture=tmpgesture;
probmodel=tmpmodel;
recogprob=((tmpmodel*tmpgesture)/sum);
recognized=i;
}
}
// a gesture could be recognized
if(recogprob>0 && probmodel>0 && probgesture>0 && sum>0) {
this.lastprob=recogprob;
return recognized;
} else {
// no gesture could be recognized
return -1;
}
}
public double getLastProbability() {
return this.lastprob;
}
public void addGestureModel(GestureModel gm) {
this.gesturemodel.add(gm);
}
public GestureModel getGestureModel(int id) {
return this.gesturemodel.elementAt(id);
}
public Vector<GestureModel> getGestureModels() {
return this.gesturemodel;
}
public int getCountOfGestures() {
return this.gesturemodel.size();
}
public void clear() {
this.gesturemodel = new Vector<GestureModel>();
}
}

155
src/org/wiigee/logic/Gesture.java Executable file
View File

@@ -0,0 +1,155 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.util.Vector;
import org.wiigee.event.AccelerationEvent;
/**
* This class represents ONE movement trajectory in a
* concrete instance.
*
* @author Benjamin 'BePo' Poppinga
*/
public class Gesture implements Cloneable {
/** Min/MaxAcceleration setup manually? */
private boolean minmaxmanual;
private double minacc;
private double maxacc;
/** The complete trajectory as WiimoteAccelerationEvents
* as a vector. It's a vector because we don't want to
* loose the chronology of the stored events.
*/
private Vector<AccelerationEvent> data;
/**
* Create an empty Gesture.
*/
public Gesture() {
this.data = new Vector<AccelerationEvent>();
}
/**
* Make a deep copy of another Gesture object.
*
* @param original Another Gesture object
*/
public Gesture(Gesture original) {
this.data = new Vector<AccelerationEvent>();
Vector<AccelerationEvent> origin = original.getData();
for (int i = 0; i < origin.size(); i++) {
this.add((AccelerationEvent) origin.get(i));
}
}
/**
* Adds a new acceleration event to this gesture.
*
* @param event The WiimoteAccelerationEvent to add.
*/
public void add(AccelerationEvent event) {
this.data.add(event);
}
/**
* Returns the last acceleration added to this gesture.
*
* @return the last acceleration event added.
*/
public AccelerationEvent getLastData() {
return (AccelerationEvent) this.data.get(this.data.size() - 1);
}
/**
* Returns the whole chronological sequence of accelerations as
* a vector.
*
* @return chronological sequence of accelerations.
*/
public Vector<AccelerationEvent> getData() {
return this.data;
}
/**
* Removes the first element of the acceleration queue of a gesture
*/
public void removeFirstData() {
this.data.remove(0);
}
public int getCountOfData() {
return this.data.size();
}
public void setMaxAndMinAcceleration(double max, double min) {
this.maxacc = max;
this.minacc = min;
this.minmaxmanual = true;
}
public double getMaxAcceleration() {
if(!this.minmaxmanual) {
double maxacc = Double.MIN_VALUE;
for(int i=0; i<this.data.size(); i++) {
if(Math.abs(this.data.get(i).getX()) > maxacc) {
maxacc=Math.abs(this.data.get(i).getX());
}
if(Math.abs(this.data.get(i).getY()) > maxacc) {
maxacc=Math.abs(this.data.get(i).getY());
}
if(Math.abs(this.data.get(i).getZ()) > maxacc) {
maxacc=Math.abs(this.data.get(i).getZ());
}
}
return maxacc;
} else {
return this.maxacc;
}
}
public double getMinAcceleration() {
if(!this.minmaxmanual) {
double minacc = Double.MAX_VALUE;
for(int i=0; i<this.data.size(); i++) {
if(Math.abs(this.data.get(i).getX()) < minacc) {
minacc=Math.abs(this.data.get(i).getX());
}
if(Math.abs(this.data.get(i).getY()) < minacc) {
minacc=Math.abs(this.data.get(i).getY());
}
if(Math.abs(this.data.get(i).getZ()) < minacc) {
minacc=Math.abs(this.data.get(i).getZ());
}
}
return minacc;
} else {
return this.minacc;
}
}
}

View File

@@ -0,0 +1,205 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.util.Vector;
import org.wiigee.event.AccelerationEvent;
import org.wiigee.util.Log;
/**
* This Class units a Quantizer-Component and an Model-Component.
* In this implementation a k-mean-algorithm for quantization and
* a hidden markov model as instance for the model has been used.
*
* @author Benjamin 'BePo' Poppinga
*/
public class GestureModel {
/** The number of states the hidden markov model consists of */
private int numStates;
/** The number of observations for the hmm and k-mean */
private int numObservations;
/** The quantization component */
private Quantizer quantizer;
/** The statistical model, hidden markov model */
private HMM markovmodell;
/** The default probability of this gesturemodel,
* needed for the bayes classifier */
private double defaultprobability;
/** Creates a Unit (Quantizer&Model).
*
* @param id
* int representation of a gesture "name"/class.
*/
public GestureModel() {
this.numStates=8; // n=8 states empirical value
this.numObservations=14; // k=14 observations empirical value
this.markovmodell = new HMM(numStates, numObservations); // init model
this.quantizer = new Quantizer(numStates); // init quantizer
}
/**
* Trains the model to a set of motion-sequences, representing
* different evaluations of a gesture
*
* @param trainsequence a vector of gestures
*/
public void train(Vector<Gesture> trainsequence) {
// summarize all vectors from the different gestures in one
// gesture called sum.
double maxacc=0;
double minacc=0;
Gesture sum = new Gesture();
for(int i=0; i<trainsequence.size(); i++) {
Vector<AccelerationEvent> t = trainsequence.elementAt(i).getData();
// add the max and min acceleration, we later get the average
maxacc+=trainsequence.elementAt(i).getMaxAcceleration();
minacc+=trainsequence.elementAt(i).getMinAcceleration();
// transfer every single accelerationevent of each gesture to
// the new gesture sum
for(int j=0; j<trainsequence.elementAt(i).getData().size(); j++) {
sum.add(t.elementAt(j));
}
}
// get the average and set it to the sum gesture
sum.setMaxAndMinAcceleration(maxacc/trainsequence.size(), minacc/trainsequence.size());
// train the centeroids of the quantizer with this master gesture sum.
this.quantizer.trainCenteroids(sum);
// convert gesture vector to a sequence of discrete values
Vector<int[]> seqs = new Vector<int[]>();
for(int i=0; i<trainsequence.size(); i++) {
seqs.add(this.quantizer.getObservationSequence(trainsequence.elementAt(i)));
}
// train the markov model with this derived discrete sequences
this.markovmodell.train(seqs);
// set the default probability for use with the bayes classifier
this.setDefaultProbability(trainsequence);
}
/**
* Returns the probability that a gesture matches to this
* gesture model.
*
* @param gesture a gesture to test.
* @return probability that the gesture belongs to this gesture
* model.
*/
public double matches(Gesture gesture) {
int[] sequence = quantizer.getObservationSequence(gesture);
return this.markovmodell.getProbability(sequence);
}
/**
* For debug purposes or very technical interested people. :)
*/
public void printMap() {
Log.write("Gesture Quantizer-Map:");
this.quantizer.printMap();
}
/***
* For debug purposes or very technical interested people. :)
* @return
*/
public void print() {
Log.write("HMM-Print:");
this.markovmodell.print();
Log.write("Quanzizer-Print:");
this.quantizer.printMap();
}
public int getNumStates() {
return this.numStates;
}
public int getNumObservations() {
return this.numObservations;
}
/**
* Returns the model probability for bayes.
*
* @return
* the model probability
*/
public double getDefaultProbability() {
return this.defaultprobability;
}
/**
* Since the bayes classifier needs a model probability for
* each model this has to be set once after training. As model
* probability the average probability value has been choosen.
*
* TODO: try lowest or highest model probability as alternative
*
* @param defsequence the vector of training sequences.
*/
private void setDefaultProbability(Vector<Gesture> defsequence) {
double prob=0;
for(int i=0; i<defsequence.size(); i++) {
prob+=this.matches(defsequence.elementAt(i));
}
this.defaultprobability=(prob)/defsequence.size();
}
public void setDefaultProbability(double prob) {
this.defaultprobability = prob;
Log.write("def-prob. set to = "+this.defaultprobability);
}
public Quantizer getQuantizer() {
return this.quantizer;
}
public void setQuantizer(Quantizer q) {
this.quantizer = q;
}
public HMM getHMM() {
return this.markovmodell;
}
public void setHMM(HMM hmm) {
this.markovmodell = hmm;
}
}

314
src/org/wiigee/logic/HMM.java Executable file
View File

@@ -0,0 +1,314 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.text.DecimalFormat;
import java.util.Vector;
import org.wiigee.util.Log;
/**
* This is a Hidden Markov Model implementation which internally provides
* the basic algorithms for training and recognition (forward and backward
* algorithm). Since a regular Hidden Markov Model doesn't provide a possibility
* to train multiple sequences, this implementation has been optimized for this
* purposes using some state-of-the-art technologies described in several papers.
*
* @author Benjamin 'BePo' Poppinga
*
*/
public class HMM {
/** The number of states */
protected int numStates;
/** The number of observations */
protected int numObservations;
/** The initial probabilities for each state: p[state] */
protected double pi[];
/** The state change probability to switch from state A to
* state B: a[stateA][stateB] */
protected double a[][];
/** The probability to emit symbol S in state A: b[stateA][symbolS] */
protected double b[][];
/**
* Initialize the Hidden Markov Model in a left-to-right version.
*
* @param numStates Number of states
* @param numObservations Number of observations
*/
public HMM(int numStates, int numObservations) {
this.numStates = numStates;
this.numObservations = numObservations;
pi = new double[numStates];
a = new double[numStates][numStates];
b = new double[numStates][numObservations];
this.reset();
}
/**
* Reset the Hidden Markov Model to the initial left-to-right values.
*
*/
private void reset() {
int jumplimit = 2;
// set startup probability
pi[0] = 1;
for(int i=1; i<numStates; i++) {
pi[i] = 0;
}
// set state change probabilities in the left-to-right version
// NOTE: i now that this is dirty and very static. :)
for(int i=0; i<numStates; i++) {
for(int j=0; j<numStates; j++) {
if(i==numStates-1 && j==numStates-1) { // last row
a[i][j] = 1.0;
} else if(i==numStates-2 && j==numStates-2) { // next to last row
a[i][j] = 0.5;
} else if(i==numStates-2 && j==numStates-1) { // next to last row
a[i][j] = 0.5;
} else if(i<=j && i>j-jumplimit-1) {
a[i][j] = 1.0/(jumplimit+1);
} else {
a[i][j] = 0.0;
}
}
}
// emission probability
for(int i=0; i<numStates; i++) {
for(int j=0; j<numObservations; j++) {
b[i][j] = 1.0/(double)numObservations;
}
}
}
/**
* Trains the Hidden Markov Model with multiple sequences.
* This method is normally not known to basic hidden markov
* models, because they usually use the Baum-Welch-Algorithm.
* This method is NOT the traditional Baum-Welch-Algorithm.
*
* If you want to know in detail how it works please consider
* my Individuelles Projekt paper on the wiigee Homepage. Also
* there exist some english literature on the world wide web.
* Try to search for some papers by Rabiner or have a look at
* Vesa-Matti Mäntylä - "Discrete Hidden Markov Models with
* application to isolated user-dependent hand gesture recognition".
*
*/
public void train(Vector<int[]> trainsequence) {
double[][] a_new = new double[a.length][a.length];
double[][] b_new = new double[b.length][b[0].length];
// re calculate state change probability a
for(int i=0; i<a.length; i++) {
for(int j=0; j<a[i].length; j++) {
double zaehler=0;
double nenner=0;
for(int k=0; k<trainsequence.size(); k++) {
int[] sequence = trainsequence.elementAt(k);
double[][] fwd = this.forwardProc(sequence);
double[][] bwd = this.backwardProc(sequence);
double prob = this.getProbability(sequence);
double zaehler_innersum=0;
double nenner_innersum=0;
for(int t=0; t<sequence.length-1; t++) {
zaehler_innersum+=fwd[i][t]*a[i][j]*b[j][sequence[t+1]]*bwd[j][t+1];
nenner_innersum+=fwd[i][t]*bwd[i][t];
}
zaehler+=(1/prob)*zaehler_innersum;
nenner+=(1/prob)*nenner_innersum;
} // k
a_new[i][j] = zaehler/nenner;
} // j
} // i
// re calculate emission probability b
for(int i=0; i<b.length; i++) { // zustaende
for(int j=0; j<b[i].length; j++) { // symbole
double zaehler=0;
double nenner=0;
for(int k=0; k<trainsequence.size(); k++) {
int[] sequence = trainsequence.elementAt(k);
double[][] fwd = this.forwardProc(sequence);
double[][] bwd = this.backwardProc(sequence);
double prob = this.getProbability(sequence);
double zaehler_innersum=0;
double nenner_innersum=0;
for(int t=0; t<sequence.length-1; t++) {
if(sequence[t]==j) {
zaehler_innersum+=fwd[i][t]*bwd[i][t];
}
nenner_innersum+=fwd[i][t]*bwd[i][t];
}
zaehler+=(1/prob)*zaehler_innersum;
nenner+=(1/prob)*nenner_innersum;
} // k
b_new[i][j] = zaehler/nenner;
} // j
} // i
this.a=a_new;
this.b=b_new;
}
/**
* Traditional Forward Algorithm.
*
* @param o the observationsequence O
* @return Array[State][Time]
*
*/
protected double[][] forwardProc(int[] o) {
double[][] f = new double[numStates][o.length];
for (int l = 0; l < f.length; l++) {
f[l][0] = pi[l] * b[l][o[0]];
}
for (int i = 1; i < o.length; i++) {
for (int k = 0; k < f.length; k++) {
double sum = 0;
for (int l = 0; l < numStates; l++) {
sum += f[l][i-1] * a[l][k];
}
f[k][i] = sum * b[k][o[i]];
}
}
return f;
}
/**
* Returns the probability that a observation sequence O belongs
* to this Hidden Markov Model without using the bayes classifier.
* Internally the well known forward algorithm is used.
*
* @param o observation sequence
* @return probability that sequence o belongs to this hmm
*/
public double getProbability(int[] o) {
double prob = 0.0;
double[][] forward = this.forwardProc(o);
// add probabilities
for (int i = 0; i < forward.length; i++) { // for every state
prob += forward[i][forward[i].length - 1];
}
return prob;
}
/**
* Backward algorithm.
*
* @param o observation sequence o
* @return Array[State][Time]
*/
protected double[][] backwardProc(int[] o) {
int T = o.length;
double[][] bwd = new double[numStates][T];
/* Basisfall */
for (int i = 0; i < numStates; i++)
bwd[i][T - 1] = 1;
/* Induktion */
for (int t = T - 2; t >= 0; t--) {
for (int i = 0; i < numStates; i++) {
bwd[i][t] = 0;
for (int j = 0; j < numStates; j++)
bwd[i][t] += (bwd[j][t + 1] * a[i][j] * b[j][o[t + 1]]);
}
}
return bwd;
}
/**
* Prints everything about this model, including
* all values. For debug purposes or if you want
* to comprehend what happend to the model.
*
*/
public void print() {
DecimalFormat fmt = new DecimalFormat();
fmt.setMinimumFractionDigits(5);
fmt.setMaximumFractionDigits(5);
for (int i = 0; i < numStates; i++)
Log.write("pi(" + i + ") = " + fmt.format(pi[i]));
Log.write("");
for (int i = 0; i < numStates; i++) {
for (int j = 0; j < numStates; j++)
Log.write("a(" + i + "," + j + ") = "
+ fmt.format(a[i][j]) + " ");
Log.write("");
}
Log.write("");
for (int i = 0; i < numStates; i++) {
for (int k = 0; k < numObservations; k++)
Log.write("b(" + i + "," + k + ") = "
+ fmt.format(b[i][k]) + " ");
Log.write("");
}
}
public double[] getPi() {
return this.pi;
}
public void setPi(double[] pi) {
this.pi = pi;
}
public double[][] getA() {
return this.a;
}
public void setA(double[][] a) {
this.a = a;
}
public double[][] getB() {
return this.b;
}
public void setB(double[][] b) {
this.b=b;
}
}

View File

@@ -0,0 +1,449 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.text.*;
import java.util.Vector;
import java.lang.Math;
import org.wiigee.util.Log;
/**
* This is a Hidden Markov Model implementation which internally provides
* the basic algorithms for training and recognition (forward and backward
* algorithm). Since a regular Hidden Markov Model doesn't provide a possibility
* to train multiple sequences, this implementation has been optimized for this
* purposes using some state-of-the-art technologies described in several papers.
*
* @author Benjamin 'BePo' Poppinga
*
*/
public class PreciseHMM {
/** The number of states */
private int numStates;
/** The number of observations */
private int sigmaSize;
/** The initial probabilities for each state: p[state] */
public double pi[];
/** The state change probability to switch from state A to
* state B: a[stateA][stateB] */
public double a[][];
/** The probability to emit symbol S in state A: b[stateA][symbolS] */
public double b[][];
/**
* Initialize the Hidden Markov Model in a left-to-right version.
*
* @param numStates Number of states
* @param sigmaSize Number of observations
*/
public PreciseHMM(int numStates, int sigmaSize) {
this.numStates = numStates;
this.sigmaSize = sigmaSize;
pi = new double[numStates];
a = new double[numStates][numStates];
b = new double[numStates][sigmaSize];
this.reset();
}
/**
* Reset the Hidden Markov Model to the initial left-to-right values.
*
*/
private void reset() {
int jumplimit = 2;
// set startup probability
pi[0] = 1.0;
for(int i=1; i<numStates; i++) {
pi[i] = 0;
}
// set state change probabilities in the left-to-right version
// NOTE: i now that this is dirty and very static. :)
for(int i=0; i<numStates; i++) {
for(int j=0; j<numStates; j++) {
if(i==numStates-1 && j==numStates-1) { // last row
a[i][j] = 1.0;
} else if(i==numStates-2 && j==numStates-2) { // next to last row
a[i][j] = 0.5;
} else if(i==numStates-2 && j==numStates-1) { // next to last row
a[i][j] = 0.5;
} else if(i<=j && i>j-jumplimit-1) {
a[i][j] = 1.0/(jumplimit+1);
} else {
a[i][j] = 0.0;
}
}
}
// emission probability
for(int i=0; i<numStates; i++) {
for(int j=0; j<sigmaSize; j++) {
b[i][j] = 1.0/(double)sigmaSize;
}
}
}
/**
* Trains the Hidden Markov Model with multiple sequences.
* This method is normally not known to basic hidden markov
* models, because they usually use the Baum-Welch-Algorithm.
* This method is NOT the traditional Baum-Welch-Algorithm.
*
* If you want to know in detail how it works please consider
* my Individuelles Projekt paper on the wiigee Homepage. Also
* there exist some english literature on the world wide web.
* Try to search for some papers by Rabiner or have a look at
* Vesa-Matti Mäntylä - "Discrete Hidden Markov Models with
* application to isolated user-dependent hand gesture recognition".
*
*/
public void train(Vector<int[]> trainsequence) {
double[][] a_new = new double[a.length][a.length];
double[][] b_new = new double[b.length][b[0].length];
// re calculate state change probability a
for(int i=0; i<a.length; i++) {
for(int j=0; j<a[i].length; j++) {
double zaehler=0;
double nenner=0;
for(int k=0; k<trainsequence.size(); k++) {
//this.reset();
int[] sequence = trainsequence.elementAt(k);
double[] sf = this.calculateScalingFactor(sequence);
double[][] fwd = this.scaledForwardProc(sequence);
double[][] bwd = this.scaledBackwardProc(sequence, sf);
double zaehler_innersum=0;
double nenner_innersum=0;
for(int t=0; t<sequence.length-1; t++) {
zaehler_innersum+=fwd[i][t]*a[i][j]*b[j][sequence[t+1]]*bwd[j][t+1]*sf[t+1];
nenner_innersum+=fwd[i][t]*bwd[i][t];
}
zaehler+=zaehler_innersum;
nenner+=nenner_innersum;
} // k
a_new[i][j] = zaehler/nenner;
} // j
} // i
// re calculate emission probability b
for(int i=0; i<b.length; i++) { // zustaende
for(int j=0; j<b[i].length; j++) { // symbole
double zaehler=0;
double nenner=0;
for(int k=0; k<trainsequence.size(); k++) {
//this.reset();
int[] sequence = trainsequence.elementAt(k);
double[] sf = this.calculateScalingFactor(sequence);
double[][] fwd = this.scaledForwardProc(sequence);
double[][] bwd = this.scaledBackwardProc(sequence, sf);
double zaehler_innersum=0;
double nenner_innersum=0;
for(int t=0; t<sequence.length-1; t++) {
if(sequence[t]==j) {
zaehler_innersum+=fwd[i][t]*bwd[i][t]*sf[t];
}
nenner_innersum+=fwd[i][t]*bwd[i][t]*sf[t];
}
zaehler+=zaehler_innersum;
nenner+=nenner_innersum;
} // k
b_new[i][j] = zaehler/nenner;
} // j
} // i
this.a=a_new;
this.b=b_new;
}
private double[] calculateScalingFactor(int[] sequence) {
// for all indexing: [state][time]
double[][] fwd = this.forwardProc(sequence); // normal
double[][] help = new double[fwd.length][fwd[0].length];
double[][] scaled = new double[fwd.length][fwd[0].length];
double[] sf = new double[sequence.length];
// ************** BASIS *************
// Basis, fixed t=0
// setup, because needed for further calculations
for(int i=0; i<help.length; i++) {
help[i][0] = fwd[i][0];
}
// setup initial scaled array
double sum0 = 0;
for(int i=0; i<help.length; i++) {
sum0+=help[i][0];
}
for(int i=0; i<scaled.length; i++) {
scaled[i][0] = help[i][0] / sum0;
}
// calculate scaling factor
sf[0] = 1/sum0;
// **************** INDUCTION ***************
// end of fixed t = 0
// starting with t>1 to sequence.length
// induction, further calculations
for(int t=1; t<sequence.length; t++) {
// calculate help
for(int i=0; i<help.length; i++) {
for(int j=0; j<this.numStates; j++) {
help[i][t]+=scaled[j][t-1]*a[j][i]*b[i][sequence[t]];
}
}
double sum = 0;
for(int i=0; i<help.length; i++) {
sum+=help[i][t];
}
for(int i=0; i<scaled.length; i++) {
scaled[i][t] = help[i][t] / sum;
}
// calculate scaling factor
sf[t] = 1 / sum;
} // t
return sf;
} // calculateScalingFactor
/***
* Returns the scaled Forward variable.
* TODO: Maybe try out if the other precalculated method is faster.
* @param sequence
* @return
*/
private double[][] scaledForwardProc(int[] sequence) {
double[][] fwd = this.forwardProc(sequence);
double[][] out = new double[fwd.length][fwd[0].length];
for(int i=0; i<fwd.length; i++) {
for(int t=0; t<sequence.length; t++) {
double sum = 0;
for(int j=0; j<fwd.length; j++) {
sum+=fwd[j][t];
}
out[i][t] = fwd[i][t] / sum;
}
}
return out;
}
private double[][] scaledBackwardProc(int[] sequence, double[] sf) {
double[][] bwd = this.backwardProc(sequence);
double[][] out = new double[bwd.length][bwd[0].length];
for(int i=0; i<bwd.length; i++) {
for(int t=0; t<sequence.length; t++) {
out[i][t]=1;
for(int r=t+1; r<sequence.length; r++) {
out[i][t]*=sf[r]*bwd[i][t];
}
}
}
return out;
}
/**
* Returns the probability that a observation sequence O belongs
* to this Hidden Markov Model without using the bayes classifier.
* Internally the well known forward algorithm is used.
*
* @param o observation sequence
* @return probability that sequence o belongs to this hmm
*/
public double getProbability(int[] o) {
return scaledViterbi(o);
//return sProbability(o);
/*double prob = 0.0;
double[][] forward = this.forwardProc(o);
// add probabilities
for (int i = 0; i < forward.length; i++) { // for every state
prob += forward[i][forward[i].length - 1];
}
return prob;*/
}
public double sProbability(int[] o) {
double prod = 1.0;
double[][] fwd = this.scaledForwardProc(o);
for(int t=0; t<o.length; t++) {
double sum = 0.0;
for(int i=0; i<this.numStates; i++) {
sum+=fwd[i][t];
}
sum = 1/sum;
prod*=sum;
}
return 1/prod;
}
public double scaledViterbi(int[] o) {
double[][] phi = new double[this.numStates][o.length]; //phi[states][oseq]
// init
for(int i=0; i<this.numStates; i++) {
phi[i][0] = Math.log(pi[i]) + Math.log(b[i][o[0]]);
}
// induction
for(int t=1; t<o.length; t++) {
for(int j=0; j<this.numStates; j++) {
double max = Double.NEGATIVE_INFINITY;
for(int i=0; i<this.numStates; i++) {
double val = phi[i][t-1] + Math.log(this.a[i][j]);
if(val>max) {
max = val;
}
}
phi[j][t] = max + Math.log(this.b[j][o[t]]);
}
}
// conclusion
double lp = Double.NEGATIVE_INFINITY;
for(int i=0; i<this.numStates; i++) {
if(phi[i][o.length-1]>lp) {
lp = phi[i][o.length-1];
}
}
//Log.write("log p = "+lp);
//return lp;
// we now have log10(p) calculated, transform to p.
Log.write("prob = "+Math.exp(lp));
return Math.exp(lp);
//return Math.pow(10, lp);
}
/**
* Traditional Forward Algorithm.
*
* @param o the observationsequence O
* @return Array[State][Time]
*
*/
private double[][] forwardProc(int[] o) {
double[][] f = new double[numStates][o.length];
for (int l = 0; l < f.length; l++) {
f[l][0] = pi[l] * b[l][o[0]];
}
for (int i = 1; i < o.length; i++) {
for (int k = 0; k < f.length; k++) {
double sum = 0;
for (int l = 0; l < numStates; l++) {
sum += f[l][i-1] * a[l][k];
}
f[k][i] = sum * b[k][o[i]];
}
}
return f;
}
/**
* Backward algorithm.
*
* @param o observation sequence o
* @return Array[State][Time]
*/
private double[][] backwardProc(int[] o) {
int T = o.length;
double[][] bwd = new double[numStates][T];
/* Basisfall */
for (int i = 0; i < numStates; i++)
bwd[i][T - 1] = 1;
/* Induktion */
for (int t = T - 2; t >= 0; t--) {
for (int i = 0; i < numStates; i++) {
bwd[i][t] = 0;
for (int j = 0; j < numStates; j++)
bwd[i][t] += (bwd[j][t + 1] * a[i][j] * b[j][o[t + 1]]);
}
}
return bwd;
}
/**
* Prints everything about this model, including
* all values. For debug purposes or if you want
* to comprehend what happend to the model.
*
*/
public void print() {
DecimalFormat fmt = new DecimalFormat();
fmt.setMinimumFractionDigits(10);
fmt.setMaximumFractionDigits(10);
for (int i = 0; i < numStates; i++)
Log.write("pi(" + i + ") = " + fmt.format(pi[i]));
Log.write("");
for (int i = 0; i < numStates; i++) {
for (int j = 0; j < numStates; j++)
Log.write("a(" + i + "," + j + ") = "
+ fmt.format(a[i][j]) + " ");
Log.write("");
}
Log.write("");
for (int i = 0; i < numStates; i++) {
for (int k = 0; k < sigmaSize; k++)
Log.write("b(" + i + "," + k + ") = "
+ fmt.format(b[i][k]) + " ");
Log.write("");
}
}
public double[][] getA() {
return this.a;
}
public void setA(double[][] a) {
this.a = a;
}
public double[][] getB() {
return this.b;
}
public void setB(double[][] b) {
this.b=b;
}
}

View File

@@ -0,0 +1,72 @@
package org.wiigee.logic;
import java.util.Vector;
import org.wiigee.event.AccelerationEvent;
import org.wiigee.event.ButtonPressedEvent;
import org.wiigee.event.ButtonReleasedEvent;
import org.wiigee.event.AccelerationListener;
import org.wiigee.event.ButtonListener;
import org.wiigee.event.GestureEvent;
import org.wiigee.event.GestureListener;
import org.wiigee.event.MotionStartEvent;
import org.wiigee.event.MotionStopEvent;
import org.wiigee.util.Log;
public abstract class ProcessingUnit implements AccelerationListener, ButtonListener {
// Classifier
protected Classifier classifier;
// Listener
private Vector<GestureListener> gesturelistener = new Vector<GestureListener>();
public ProcessingUnit() {
this.classifier = new Classifier();
}
/**
* Add an GestureListener to receive GestureEvents.
*
* @param g
* Class which implements GestureListener interface.
*/
public void addGestureListener(GestureListener g) {
this.gesturelistener.add(g);
}
protected void fireGestureEvent(boolean valid, int id, double probability) {
GestureEvent w = new GestureEvent(this, valid, id, probability);
for (int i = 0; i < this.gesturelistener.size(); i++) {
this.gesturelistener.get(i).gestureReceived(w);
}
}
public abstract void accelerationReceived(AccelerationEvent event);
public abstract void buttonPressReceived(ButtonPressedEvent event);
public abstract void buttonReleaseReceived(ButtonReleasedEvent event);
public abstract void motionStartReceived(MotionStartEvent event);
public abstract void motionStopReceived(MotionStopEvent event);
/**
* Resets the complete gesturemodel. After reset no gesture is known
* to the system.
*/
public void reset() {
if (this.classifier.getCountOfGestures() > 0) {
this.classifier.clear();
Log.write("### Model reset ###");
} else {
Log.write("There doesn't exist any data to reset.");
}
}
// File IO
public abstract void loadGesture(String filename);
public abstract void saveGesture(int id, String filename);
}

View File

@@ -0,0 +1,309 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.util.Vector;
import org.wiigee.event.AccelerationEvent;
import org.wiigee.util.Log;
/**
* This class implements a quantization component. In this case a
* k-mean-algorithm is used. In this case the initial values of the algorithm
* are ordered as two intersected circles, representing an abstract globe with
* k=14 elements. As a special feature the radius of this globe would be
* calculated dynamically before the training of this component.
*
* @author Benjamin 'BePo' Poppinga
*/
public class Quantizer {
/** This is the initial radius of this model. */
private double radius;
/** Number of states from the following Hidden Markov Model */
private int numStates;
/** The representation of the so called Centeroids */
private double[][] map;
/** True, if map is already trained. */
private boolean maptrained;
/**
* Initialize a empty quantizer. The states variable is necessary since some
* algorithms need this value to calculate their values correctly.
*
* @param numStates
* number of hidden markov model states
*/
public Quantizer(int numStates) {
this.numStates = numStates;
this.map = new double[14][3];
this.maptrained = false;
}
/**
* Trains this Quantizer with a specific gesture. This means that the
* positions of the centeroids would adapt to this training gesture. In our
* case this would happen with a summarized virtual gesture, containing all
* the other gestures.
*
* @param gesture
* the summarized virtual gesture
*/
public void trainCenteroids(Gesture gesture) {
Vector<AccelerationEvent> data = gesture.getData();
double pi = Math.PI;
this.radius = (gesture.getMaxAcceleration() + gesture
.getMinAcceleration()) / 2;
Log.write("Using radius: " + this.radius);
// x , z , y
if (!this.maptrained) {
this.maptrained = true;
this.map[0] = new double[] { this.radius, 0.0, 0.0 };
this.map[1] = new double[] { Math.cos(pi / 4) * this.radius, 0.0,
Math.sin(pi / 4) * this.radius };
this.map[2] = new double[] { 0.0, 0.0, this.radius };
this.map[3] = new double[] { Math.cos(pi * 3 / 4) * this.radius,
0.0, Math.sin(pi * 3 / 4) * this.radius };
this.map[4] = new double[] { -this.radius, 0.0, 0.0 };
this.map[5] = new double[] { Math.cos(pi * 5 / 4) * this.radius,
0.0, Math.sin(pi * 5 / 4) * this.radius };
this.map[6] = new double[] { 0.0, 0.0, -this.radius };
this.map[7] = new double[] { Math.cos(pi * 7 / 4) * this.radius,
0.0, Math.sin(pi * 7 / 4) * this.radius };
this.map[8] = new double[] { 0.0, this.radius, 0.0 };
this.map[9] = new double[] { 0.0, Math.cos(pi / 4) * this.radius,
Math.sin(pi / 4) * this.radius };
this.map[10] = new double[] { 0.0,
Math.cos(pi * 3 / 4) * this.radius,
Math.sin(pi * 3 / 4) * this.radius };
this.map[11] = new double[] { 0.0, -this.radius, 0.0 };
this.map[12] = new double[] { 0.0,
Math.cos(pi * 5 / 4) * this.radius,
Math.sin(pi * 5 / 4) * this.radius };
this.map[13] = new double[] { 0.0,
Math.cos(pi * 7 / 4) * this.radius,
Math.sin(pi * 7 / 4) * this.radius };
}
int[][] g_alt = new int[this.map.length][data.size()];
int[][] g = new int[this.map.length][data.size()];
do {
// Derive new Groups...
g_alt = this.copyarray(g);
g = this.deriveGroups(gesture);
// calculate new centeroids
for (int i = 0; i < this.map.length; i++) {
double zaehlerX = 0;
double zaehlerY = 0;
double zaehlerZ = 0;
int nenner = 0;
for (int j = 0; j < data.size(); j++) {
if (g[i][j] == 1) {
zaehlerX += data.elementAt(j).getX();
zaehlerY += data.elementAt(j).getY();
zaehlerZ += data.elementAt(j).getZ();
nenner++;
}
}
if (nenner > 1) { // nur wenn der nenner>0 oder >1??? ist muss
// was
// geaendert werden
// Log.write("Setze neuen Centeroid!");
this.map[i] = new double[] {(zaehlerX / (double) nenner),
(zaehlerY / (double) nenner),
(zaehlerZ / (double) nenner) };
// Log.write("Centeroid: "+i+": "+newcenteroid[0]+":"+newcenteroid[1]);
}
} // new centeroids
} while (!equalarrays(g_alt, g));
// Debug: Printout groups
/*
* for (int i = 0; i < n; i++) { for (int j = 0; j < this.data.size();
* j++) { Log.write(g[i][j] + "|"); } Log.write(""); }
*/
}
/**
* This methods looks up a Gesture to a group matrix, used by the
* k-mean-algorithm (traincenteroid method) above.
*
* @param gesture
* the gesture
*/
public int[][] deriveGroups(Gesture gesture) {
Vector<AccelerationEvent> data = gesture.getData();
int[][] groups = new int[this.map.length][data.size()];
// Calculate cartesian distance
double[][] d = new double[this.map.length][data.size()];
double[] curr = new double[3];
double[] vector = new double[3];
for (int i = 0; i < this.map.length; i++) { // zeilen
double[] ref = this.map[i];
for (int j = 0; j < data.size(); j++) { // spalten
curr[0] = data.elementAt(j).getX();
curr[1] = data.elementAt(j).getY();
curr[2] = data.elementAt(j).getZ();
vector[0] = ref[0] - curr[0];
vector[1] = ref[1] - curr[1];
vector[2] = ref[2] - curr[2];
d[i][j] = Math.sqrt((vector[0] * vector[0])
+ (vector[1] * vector[1]) + (vector[2] * vector[2]));
// Log.write(d[i][j] + "|");
}
// Log.write("");
}
// look, to which group a value belongs
for (int j = 0; j < data.size(); j++) {
double smallest = Double.MAX_VALUE;
int row = 0;
for (int i = 0; i < this.map.length; i++) {
if (d[i][j] < smallest) {
smallest = d[i][j];
row = i;
}
groups[i][j] = 0;
}
groups[row][j] = 1; // guppe gesetzt
}
// Debug output
/*
* for (int i = 0; i < groups.length; i++) { // zeilen for (int j = 0; j
* < groups[i].length; j++) { Log.write(groups[i][j] + "|"); }
* Log.write(""); }
*/
return groups;
}
/**
* With this method you can transform a gesture to a discrete symbol
* sequence with values between 0 and granularity (number of observations).
*
* @param gesture
* Gesture to get the observationsequence to.
*/
public int[] getObservationSequence(Gesture gesture) {
int[][] groups = this.deriveGroups(gesture);
Vector<Integer> sequence = new Vector<Integer>();
// Log.write("Visible symbol sequence: ");
for (int j = 0; j < groups[0].length; j++) { // spalten
for (int i = 0; i < groups.length; i++) { // zeilen
if (groups[i][j] == 1) {
// Log.write(" "+ i);
sequence.add(i);
break;
}
}
}
// die sequenz darf nicht zu kurz sein... mindestens so lang
// wie die anzahl der zustände. weil sonst die formeln nicht klappen.
// english: this is very dirty! it have to be here because if not
// too short sequences would cause an error. i've to think about a
// better resolution than copying the old value a few time.
while (sequence.size() < this.numStates) {
sequence.add(sequence.elementAt(sequence.size() - 1));
// Log.write(" "+sequence.elementAt(sequence.size()-1));
}
// Log.write("");
int[] out = new int[sequence.size()];
for (int i = 0; i < sequence.size(); i++) {
out[i] = sequence.elementAt(i);
}
return out;
}
/**
* Prints out the current centeroids-map. Its for debug or technical
* interests.
*/
public void printMap() {
Log.write("Centeroids:");
for (int i = 0; i < this.map.length; i++) {
Log.write(i + ". :" + this.map[i][0] + ":"
+ this.map[i][1] + ":" + this.map[i][2]);
}
}
/**
* Function to deepcopy an array.
*/
private int[][] copyarray(int[][] alt) {
int[][] neu = new int[alt.length][alt[0].length];
for (int i = 0; i < alt.length; i++) {
for (int j = 0; j < alt[i].length; j++) {
neu[i][j] = alt[i][j];
}
}
return neu;
}
/**
* Function to look if the two arrays containing the same values.
*/
private boolean equalarrays(int[][] one, int[][] two) {
for (int i = 0; i < one.length; i++) {
for (int j = 0; j < one[i].length; j++) {
if (!(one[i][j] == two[i][j])) {
return false;
}
}
}
return true;
}
public double getRadius() {
return this.radius;
}
public double[][] getHashMap() {
return this.map;
}
public void setUpManually(double[][] map, double radius) {
this.map = map;
this.radius = radius;
}
}

View File

@@ -0,0 +1,188 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.logic;
import java.util.Vector;
import org.wiigee.event.*;
import org.wiigee.util.Log;
/**
* This class analyzes the AccelerationEvents emitted from a Wiimote
* and further creates and manages the different models for each type
* of gesture.
*
* @author Benjamin 'BePo' Poppinga
*/
public class TriggeredProcessingUnit extends ProcessingUnit {
// gesturespecific values
private Gesture current; // current gesture
private Vector<Gesture> trainsequence;
// State variables
private boolean learning, analyzing;
public TriggeredProcessingUnit() {
super();
this.learning=false;
this.analyzing=false;
this.current=new Gesture();
this.trainsequence=new Vector<Gesture>();
}
/**
* Since this class implements the WiimoteListener this procedure is
* necessary. It contains the filtering (directional equivalence filter)
* and adds the incoming data to the current motion, we want to train
* or recognize.
*
* @param event The acceleration event which has to be processed by the
* directional equivalence filter and which has to be added to the current
* motion in recognition or training process.
*/
public void accelerationReceived(AccelerationEvent event) {
if(this.learning || this.analyzing) {
this.current.add(event); // add event to gesture
}
}
/**
* This method is from the WiimoteListener interface. A button press
* is used to control the data flow inside the structures.
*
*/
public void buttonPressReceived(ButtonPressedEvent event) {
this.handleStartEvent(event);
}
public void buttonReleaseReceived(ButtonReleasedEvent event) {
this.handleStopEvent(event);
}
public void motionStartReceived(MotionStartEvent event) {
// this.handleStartEvent(event);
}
public void motionStopReceived(MotionStopEvent event) {
// this.handleStopEvent(event);
}
public void handleStartEvent(ActionStartEvent event) {
// TrainButton = record a gesture for learning
if((!this.analyzing && !this.learning) &&
event.isTrainInitEvent()) {
Log.write("Training started!");
this.learning=true;
}
// RecognitionButton = record a gesture for recognition
if((!this.analyzing && !this.learning) &&
event.isRecognitionInitEvent()) {
Log.write("Recognition started!");
this.analyzing=true;
}
// CloseGestureButton = starts the training of the model with multiple
// recognized gestures, contained in trainsequence
if((!this.analyzing && !this.learning) &&
event.isCloseGestureInitEvent()) {
if(this.trainsequence.size()>0) {
Log.write("Training the model with "+this.trainsequence.size()+" gestures...");
this.learning=true;
GestureModel m = new GestureModel();
m.train(this.trainsequence);
m.print();
this.classifier.addGestureModel(m);
this.trainsequence=new Vector<Gesture>();
this.learning=false;
} else {
Log.write("There is nothing to do. Please record some gestures first.");
}
}
}
public void handleStopEvent(ActionStopEvent event) {
if(this.learning) { // button release and state=learning, stops learning
if(this.current.getCountOfData()>0) {
Log.write("Finished recording (training)...");
Log.write("Data: "+this.current.getCountOfData());
Gesture gesture = new Gesture(this.current);
this.trainsequence.add(gesture);
this.current=new Gesture();
this.learning=false;
} else {
Log.write("There is no data.");
Log.write("Please train the gesture again.");
this.learning=false; // ?
}
}
else if(this.analyzing) { // button release and state=analyzing, stops analyzing
if(this.current.getCountOfData()>0) {
Log.write("Finished recording (recognition)...");
Log.write("Compare gesture with "+this.classifier.getCountOfGestures()+" other gestures.");
Gesture gesture = new Gesture(this.current);
int recognized = this.classifier.classifyGesture(gesture);
if(recognized!=-1) {
double recogprob = this.classifier.getLastProbability();
this.fireGestureEvent(true, recognized, recogprob);
Log.write("######");
Log.write("Gesture No. "+recognized+" recognized: "+recogprob);
Log.write("######");
} else {
this.fireGestureEvent(false, 0, 0.0);
Log.write("######");
Log.write("No gesture recognized.");
Log.write("######");
}
this.current=new Gesture();
this.analyzing=false;
} else {
Log.write("There is no data.");
Log.write("Please recognize the gesture again.");
this.analyzing=false; // ?
}
}
}
@Override
public void loadGesture(String filename) {
GestureModel g = org.wiigee.util.FileIO.readFromFile(filename);
this.classifier.addGestureModel(g);
}
@Override
public void saveGesture(int id, String filename) {
org.wiigee.util.FileIO.writeToFile(this.classifier.getGestureModel(id), filename);
}
}

View File

@@ -0,0 +1,233 @@
/*
* wiigee - accelerometerbased gesture recognition
* Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
*
* Developed at University of Oldenburg
* Contact: wiigee@benjaminpoppinga.de
*
* This file is part of wiigee.
*
* wiigee is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.wiigee.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.wiigee.logic.GestureModel;
import org.wiigee.logic.HMM;
import org.wiigee.logic.Quantizer;
/**
* This is a static class to support saving and loading complete gestures. I've
* choosen not to use some kind of XML, because the big multidimensional arrays
* would cause a huge senseless amount of xml-data. So KISS: Keep It Simple,
* Stupid! ;) Comma-separated-vectors with some control data.
*
* @author Benjamin 'BePo' Poppinga
*
*/
public class FileIO {
public static void writeToFile(GestureModel m, String name) {
try {
// initialize file and get values
BufferedWriter out = new BufferedWriter(new FileWriter(name+".txt"));
int numStates = m.getNumStates();
int numObservations = m.getNumObservations();
double defaultProbability = m.getDefaultProbability();
Quantizer quantizer = m.getQuantizer();
HMM hmm = m.getHMM();
out.write("# numStates:");
out.newLine();
out.write(Integer.toString(numStates));
out.newLine();
out.write("# numObservations:");
out.newLine();
out.write(Integer.toString(numObservations));
out.newLine();
out.write("# defaultProbability:");
out.newLine();
out.write(Double.toString(defaultProbability));
out.newLine();
out.write("# Quantizer: Radius");
out.newLine();
out.write(Double.toString(quantizer.getRadius()));
out.newLine();
out.write("# Quantizer: MAP");
out.newLine();
double[][] map = quantizer.getHashMap();
for(int v=0; v<map.length; v++) {
double[] d = map[v];
out.write(Double.toString(d[0])+", "+Double.toString(d[1])+", "+Double.toString(d[2]));
out.newLine();
}
out.write("# HMM: PI");
out.newLine();
double[] pi = hmm.getPi();
for (int i=0; i<numStates; i++) {
if(i==numStates-1) {
out.write(Double.toString(pi[i]));
out.newLine();
} else {
out.write(Double.toString(pi[i])+", ");
}
}
out.write("# HMM: A");
out.newLine();
double[][] a = hmm.getA();
for(int i=0; i<numStates; i++) {
for(int j=0; j<numStates; j++) {
if(j==numStates-1) {
out.write(Double.toString(a[i][j]));
out.newLine();
} else {
out.write(Double.toString(a[i][j])+", ");
}
}
}
out.write("# HMM: B");
out.newLine();
double[][] b = hmm.getB();
for(int i=0; i<numStates; i++) {
for(int j=0; j<numObservations; j++) {
if(j==numObservations-1) {
out.write(Double.toString(b[i][j]));
out.newLine();
} else {
out.write(Double.toString(b[i][j])+", ");
}
}
}
out.write("# END");
// close file
out.flush();
out.close();
} catch (IOException e) {
System.out.println("Error: Write to File!");
e.printStackTrace();
}
}
public static GestureModel readFromFile(String name) {
try {
// initialize file and create values
BufferedReader in = new BufferedReader(new FileReader(name+".txt"));
int numStates = 0;
int numObservations = 0;
double defaultprobability = 0;
double radius = 0;
double[][] map = new double[numObservations][3];
double[] pi = new double[numStates];
double[][] a = new double[numStates][numStates];
double[][] b = new double[numStates][numObservations];
String line;
int position = 0;
while(in.ready()) {
line = in.readLine();
if(!line.startsWith("#")) { // isn't a comment
switch (position++) {
case 0:
numStates = Integer.parseInt(line);
break;
case 1:
numObservations = Integer.parseInt(line);
break;
case 2:
defaultprobability = Double.parseDouble(line);
break;
case 3:
radius = Double.parseDouble(line);
break;
case 4:
map = new double[numObservations][3];
for(int i=0; i<numObservations; i++) {
String s[] = line.split(", ");
double[] d = new double[] { Double.parseDouble(s[0]),
Double.parseDouble(s[1]),
Double.parseDouble(s[2]) };
map[i] = d;
line = in.ready() ? in.readLine() : "";
}
break;
case 5:
pi = new double[numStates];
String pi_row[] = line.split(", ");
for(int i=0; i<numStates; i++) {
pi[i] = Double.parseDouble(pi_row[i]);
}
break;
case 6:
a = new double[numStates][numStates];
for(int i=0; i<numStates; i++) {
String a_row[] = line.split(", ");
for(int j=0; j<numStates; j++) {
a[i][j] = Double.parseDouble(a_row[j]);
}
line = in.ready() ? in.readLine() : "";
}
break;
case 7:
b = new double[numStates][numObservations];
for(int i=0; i<numStates; i++) {
String b_row[] = line.split(", ");
for(int j=0; j<numObservations; j++) {
b[i][j] = Double.parseDouble(b_row[j]);
}
line = in.ready() ? in.readLine() : "";
}
break;
default:
System.out.println("SWITCH EMPTY!");
break;
}
}
}
GestureModel ret = new GestureModel();
ret.setDefaultProbability(defaultprobability);
Quantizer quantizer = new Quantizer(numStates);
quantizer.setUpManually(map, radius);
ret.setQuantizer(quantizer);
HMM hmm = new HMM(numStates, numObservations);
hmm.setPi(pi);
hmm.setA(a);
hmm.setB(b);
ret.setHMM(hmm);
return ret;
} catch (Exception e) {
System.out.println("Error: Read from File!");
e.printStackTrace();
}
return null; // bad error case
}
}

View File

@@ -0,0 +1,43 @@
package org.wiigee.util;
public class Log {
public static final int OFF = -1;
public static final int NORMAL = 0;
public static final int DEBUG = 1;
public static final int PRINT = 0;
public static final int FILE = 1;
public static int level = Log.NORMAL;
public static int mode = Log.PRINT;
public static void setLevel(int n) {
level = n;
}
public static void write(String s) {
write(Log.NORMAL, s, null);
}
public static void write(String s, Object o) {
write(Log.NORMAL, s, o);
}
public static void write(int n, String s, Object o) {
if(level>=n) {
if(mode==Log.PRINT) {
// console output enabled
if(o!=null) {
System.out.println(o.getClass()+": "+s);
} else {
System.out.println(s);
}
} else if(mode==Log.FILE) {
// file output enabled
// TODO
}
}
}
}

View File

@@ -0,0 +1,128 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.wiigee.logic;
import java.util.Vector;
import junit.framework.TestCase;
import org.wiigee.device.Device;
import org.wiigee.event.AccelerationEvent;
/**
*
* @author bepo
*/
public class ClassifierTest extends TestCase {
public ClassifierTest(String testName) {
super(testName);
}
@Override
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Test of classifyGesture method, of class Classifier.
*/
public void testClassifyGesture() {
// create a pseudo-device
Device d = new Device(true);
// create 3 gestures
Gesture g0 = new Gesture();
Gesture g1 = new Gesture();
Gesture g2 = new Gesture();
g0.add(new AccelerationEvent(d, 0.0, 0.0, 0.0, 0.0));
g0.add(new AccelerationEvent(d, 1.0, 1.0, 1.0, 0.0));
g0.add(new AccelerationEvent(d, 2.0, 2.0, 2.0, 0.0));
g0.add(new AccelerationEvent(d, 1.0, 1.0, 1.0, 0.0));
g1.add(new AccelerationEvent(d, -1.0, 1.0, -1.0, 0.0));
g1.add(new AccelerationEvent(d, -1.0, 3.0, -1.0, 0.0));
g1.add(new AccelerationEvent(d, -1.0, 1.0, -1.0, 0.0));
g1.add(new AccelerationEvent(d, -1.0, 3.0, -1.0, 0.0));
g2.add(new AccelerationEvent(d, -2.0, -2.0, -2.0, -2.0));
g2.add(new AccelerationEvent(d, -2.0, -2.0, -2.0, -2.0));
g2.add(new AccelerationEvent(d, -2.0, -2.0, -2.0, -2.0));
g2.add(new AccelerationEvent(d, -2.0, -2.0, -2.0, -2.0));
// create 3 gesturesets with 1 gesture each
Vector<Gesture> gs0 = new Vector<Gesture>();
Vector<Gesture> gs1 = new Vector<Gesture>();
Vector<Gesture> gs2 = new Vector<Gesture>();
gs0.add(g0);
gs1.add(g1);
gs2.add(g2);
// create three gesturemodels and train these
GestureModel gm0 = new GestureModel();
GestureModel gm1 = new GestureModel();
GestureModel gm2 = new GestureModel();
gm0.train(gs0);
gm1.train(gs1);
gm2.train(gs2);
// create a classifier and add gesturemodels
Classifier classifier = new Classifier();
classifier.addGestureModel(gm0);
classifier.addGestureModel(gm1);
classifier.addGestureModel(gm2);
// classify gesture
int result0 = classifier.classifyGesture(g0);
int result1 = classifier.classifyGesture(g1);
int result2 = classifier.classifyGesture(g2);
if((result0 != 0) ||
(result1 != 1) ||
(result2 != 2)) {
fail("Wrong gesture classified.");
}
}
/**
* Test of addGestureModel method, of class Classifier.
*/
public void testAddGestureModel() {
}
/**
* Test of getGestureModel method, of class Classifier.
*/
public void testGetGestureModel() {
}
/**
* Test of getGestureModels method, of class Classifier.
*/
public void testGetGestureModels() {
}
/**
* Test of getCountOfGestures method, of class Classifier.
*/
public void testGetCountOfGestures() {
}
/**
* Test of clear method, of class Classifier.
*/
public void testClear() {
}
}

View File

@@ -0,0 +1,73 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.wiigee.logic;
import java.util.Vector;
import junit.framework.Assert;
import junit.framework.TestCase;
/**
*
* @author bepo
*/
public class HMMTest extends TestCase {
public HMMTest(String testName) {
super(testName);
}
@Override
protected void setUp() throws Exception {
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Probabilistic test of the train method, of class HMM.
*/
public void testTrain() {
System.out.println("train");
HMM instance = new HMM(8, 14);
// setup a trainsequence
Vector<int[]> trainsequence = new Vector<int[]>();
trainsequence.add(new int[] { 0, 1, 2, 1, 6, 4, 3, 2});
trainsequence.add(new int[] { 0, 1, 2, 2, 6, 3, 3, 1});
trainsequence.add(new int[] { 0, 1, 2, 2, 6, 3, 2, 2});
// setup a failing trainsequence
int[] fail = new int[] { 5, 5, 5, 5, 5, 5, 5, 5};
// train the hmm
instance.train(trainsequence);
double probA = instance.getProbability(trainsequence.elementAt(0));
double probB = instance.getProbability(trainsequence.elementAt(1));
double probC = instance.getProbability(trainsequence.elementAt(2));
double probFAIL = instance.getProbability(fail);
System.out.println("probA = "+probA);
System.out.println("probB = "+probB);
System.out.println("probC = "+probC);
System.out.println("probFAIL = "+probFAIL);
if((probA <= 1.0E-10) ||
(probB <= 1.0E-10) ||
(probC <= 1.0E-10)) {
fail("Probabilities to low to be accurate.");
}
if(probFAIL > 0.0) {
fail("Fake probability to high.");
}
}
}