All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Pages
MarkerExample.cpp

MarkerExample demonstrates how to use the fiducial markers with MultiTouch cells and Cornerstone SDK. This example shows how marker information can be queried from the tracker and does simple visualization based on that information.

You can use virtual markers to try and run this application without actual MultiTouch Cell or printed marker. Press 'y' twice to change virtual input type to markers, and after that mouse press generates a dummy marker on screen.

MarkerExample-screenshot.png
Screenshot of the MarkerExample example

The heart of the example is a custom widget, MarkerVisualizer, that we use to extend the functionality of the basic MultiWidgets::Widget class. MarkerVisualizer will render rectangles whenever a marker is placed on the widget. We define our custom widget by inheriting from MultiWidgets::Widget:

class MarkerVisualizer : public MultiWidgets::Widget
{
public:
MarkerVisualizer()
: Widget()
{
}

Because input handling and rendering are done at separately in Cornerstone, we need to store some marker information in our input handling so we can later reference it during rendering. Namely, we need a list of markers affecting the widget and the input transformation that is used to convert the marker location from screen coordinates to widget coordinates. We store this information in two private member variables in MarkerVisualizer:

Nimble::Matrix3 m_inputTransform;

Since we are interested in markers, we override the MultiWidgets::Widget::processMarkers function. In our own implementation, we store the list of markers affecting the widget and the input transformation used to convert the marker coordinates from screen coordinates to widget coordinates:

virtual void processMarkers(MultiWidgets::GrabManager &gm, const MultiWidgets::MarkerArray &markers, float /*dt*/) OVERRIDE
{
// Store every marker affecting this widget
m_markers = markers;
// Store the input transformation for visualization in render
m_inputTransform = gm.transform3();
}

In order to visualize the markers, we override the renderContent function with our own implementation:

virtual void renderContent(Luminous::RenderContext & r) const OVERRIDE
{
const Nimble::Vector2f MARKER_SIZE(300.f, 250.f);
Luminous::Style backgroundStyle;
backgroundStyle.setFillColor(0.f, 1.f, 0.f, 1.f);
textStyle.setFillColor(0.f, 0.f, 0.f, 1.f);
// Iterate over markers affecting the widget
for(const MultiTouch::Marker & marker: m_markers) {
// Apply transformation to render context so that origin (0,0) is at the center of the marker location
auto localCenter = m_inputTransform.project(marker.centerLocation());
Nimble::Rect rr(-0.5f * MARKER_SIZE, 0.5f * MARKER_SIZE);
// Render the marker and some info about it
r.drawRect(rr, backgroundStyle);
r.drawText(QString("Code: %1, ID: %2").arg(marker.code()).arg(marker.id()), rr, textStyle);
}
}

In our implementation, we first query the number of detected markers and iterate over all of them:

// Iterate over markers affecting the widget
for(const MultiTouch::Marker & marker: m_markers) {

For every marker, we will render a rectangle and some text information about the marker in its location:

// Apply transformation to render context so that origin (0,0) is at the center of the marker location
auto localCenter = m_inputTransform.project(marker.centerLocation());
Nimble::Rect rr(-0.5f * MARKER_SIZE, 0.5f * MARKER_SIZE);
// Render the marker and some info about it
r.drawRect(rr, backgroundStyle);
r.drawText(QString("Code: %1, ID: %2").arg(marker.code()).arg(marker.id()), rr, textStyle);

The transformation of Luminous::RenderContext is local to the widget coordinates inside the renderContent function. So to draw the marker, we transform the RenderContext to the marker's location using its location and rotation and then draw a rectangle and render some text.

The application itself consist of just creating an application instance and adding a fullscreen MarkerVisualizer widget to it.

The full source code for the example is listed below:

/* Copyright (C) 2007-2013 Multi Touch Oy, Finland, http://www.multitaction.com
*
* This file is part of MultiTouch Cornerstone.
*
* All rights reserved. You may use this file only for purposes for which you
* have a specific, written permission from Multi Touch Oy.
*
*/
#include <MultiWidgets/Application.hpp>
#include <MultiWidgets/Widget.hpp>
namespace Examples
{
class MarkerVisualizer : public MultiWidgets::Widget
{
public:
MarkerVisualizer()
: Widget()
{
}
virtual void processInput(MultiWidgets::GrabManager & , float ) OVERRIDE
{
// Clear the old markers from previous input frame
m_markers.clear();
}
virtual void processMarkers(MultiWidgets::GrabManager &gm, const MultiWidgets::MarkerArray &markers, float /*dt*/) OVERRIDE
{
// Store every marker affecting this widget
m_markers = markers;
// Store the input transformation for visualization in render
m_inputTransform = gm.transform3();
}
virtual void renderContent(Luminous::RenderContext & r) const OVERRIDE
{
const Nimble::Vector2f MARKER_SIZE(300.f, 250.f);
Luminous::Style backgroundStyle;
backgroundStyle.setFillColor(0.f, 1.f, 0.f, 1.f);
textStyle.setFillColor(0.f, 0.f, 0.f, 1.f);
// Iterate over markers affecting the widget
for(const MultiTouch::Marker & marker: m_markers) {
// Apply transformation to render context so that origin (0,0) is at the center of the marker location
auto localCenter = m_inputTransform.project(marker.centerLocation());
Nimble::Rect rr(-0.5f * MARKER_SIZE, 0.5f * MARKER_SIZE);
// Render the marker and some info about it
r.drawRect(rr, backgroundStyle);
r.drawText(QString("Code: %1, ID: %2").arg(marker.code()).arg(marker.id()), rr, textStyle);
}
}
private:
Nimble::Matrix3 m_inputTransform;
};
}
int main(int argc, char ** argv)
{
if(!app.init(argc, argv))
return 1;
auto markerVisualizer = MultiWidgets::create<Examples::MarkerVisualizer>();
app.mainLayer()->addChild(markerVisualizer);
markerVisualizer->setSize(app.mainLayer()->size());
markerVisualizer->setFixed();
// Run the application:
return app.run();
}