# How to enable root login under ubuntu

First set a password for the root user:

sudo passwd root

Now unlock the root user:

sudo passwd -u root

The root user is now enable:

su - root

# How to extract tarball on Linux ?

.tar.xz

 tar xf filename.tar.xz

.tgz

 tar -zxvf filename.tgz

.tar.gz

 tar -zxvf filename.tar.gz

.tar.bz2

 tar -jxvf filename.tar.bz2

.tar

 tar xf archive.tar

.tgz

 gzip -dc filename.tgz | tar xf -

.tar.gz

 gzip -dc filename.tar.gz | tar xf -

# Quaternion normalization

Let's consider the following quaternion:

 Q=a+b.i+c.j+d.k = \left[
\begin{matrix}
a && b && c  && d
\end{matrix}
\right]

The normalization is given by the following formula:

 Q_{normalized}=\frac{Q}{\| Q \| }

Where :

 \| Q \| = \sqrt{ q.\bar{q} } = \sqrt{ \bar{q}.q }=\sqrt {a^2 + b^2 + c^2 + d^2}

General representation:

 Q_{normalized}=
\left[
\begin{matrix}
\frac{a}{\sqrt {a^2 + b^2 + c^2 + d^2}} &&
\frac{b}{\sqrt {a^2 + b^2 + c^2 + d^2}} &&
\frac{c}{\sqrt {a^2 + b^2 + c^2 + d^2}} &&
\frac{d}{\sqrt {a^2 + b^2 + c^2 + d^2}}
\end{matrix}
\right]


# Quaternions and gyroscope

A gyroscope measures the angular rate around the three axis $X$, $Y$ and $Z$ of the sensor frame named $\omega_X$, $\omega_Y$ and $\omega_Z$ respectively. By integrating this angular rate, it is theoretically possible to estimate the orientation over time. Let's define the vector $S_{\omega}$:

 S_{\omega} = \left[ \begin{matrix} 0 && \omega_x && \omega_y && \omega_z \end{matrix} \right]

Where $\omega_X$, $\omega_Y$ and $\omega_Z$ are expressed in rad/s.

Let's now consider the quaternion derivative that describes the rate of change of orientation:

 \frac{dQ_k}{dt} = \frac{1}{2}.\hat{Q}_{k-1} \otimes S_{\omega}

Where :

• $\frac{dQ_k}{dt}$ is the derivative at time step $k$ expressed in the quaternion space.
• $\hat{Q}_{k}$ is the estimated orientation at time step $k$.

By integrating the quaternion derivative it becomes possible to estimate the orientation over time:

 \hat{Q}_k = \hat{Q}_{k-1}+ \Delta_t.\frac{dQ_k}{dt}

Note that for some applications, the quaternion must be normalized after integration:

 Q_k^n=\frac{\hat{Q}_k}{\| \hat{Q}_k \| }

## Example

close all;
clear all;
clc;

%% Initial parameters

% Initial quaternion
Q(1,:)=[1 0 0 0];

% Step time
dt=0.1;

% Initial coordinates of the point
P(1,:)=[1,2,3];

%% Main loop
for i=2:500

%% Simulate gyroscope value
% pi/8 rad/s for the 250 first steps
% pi/16 rad/s for the 250 last steps
if (i<250) Sw=[0 pi/8 0 0]; else Sw=[0 0 pi/16 0]; end;

%% Update orientation
% Compute the quaternion derivative
Qdot=quaternProd(0.5*Q(i-1,:),Sw);
% Update the estimated position
Q(i,:)=Q(i-1,:)+Qdot*0.1;
% Normalize quaternion
Q(i,:)=Q(i,:)/norm(Q(i,:));

%% Update point coordinates
% Compute the associated transformation marix
M=quatern2rotMat(Q(i,:));
% Calculate the coordinate of the new point
P(i,:)=(M*P(1,:)')';
end

%% Display point trajectory
plot3 (P(:,1),P(:,2),P(:,3),'r.');
axis square equal;
grid on;
xlabel ('x');
ylabel ('y');
zlabel ('z');


# Rotation matrices

## Rotation around the X-axis

 R_x(\alpha)=
\left[
\begin{matrix}
1 && 0 && 0 && 0 \\
0 && cos(\alpha) && -sin(\alpha) && 0 \\
0 && sin(\alpha) && cos(\alpha) && 0 \\
0 && 0 && 0 && 1
\end{matrix}
\right]


## Rotation around the Y-axis

 R_y(\beta)=
\left[
\begin{matrix}
cos(\beta) && 0 && sin(\beta) && 0 \\
0 && 1 && 0 && 0 \\
-sin(\beta) && 0 && cos(\beta) && 0 \\
0 && 0 && 0 && 1
\end{matrix}
\right]


## Rotation around the Z-axis

 R_z(\gamma)=
\left[
\begin{matrix}
cos(\gamma) && -sin(\gamma) && 0 && 0 \\
sin(\gamma) && cos(\gamma) && 0 && 0 \\
0 && 0 && 1 && 0 \\
0 && 0 && 0 && 1
\end{matrix}
\right]


# Quaternion conjugate

The quaternion conjugate is denoted by $^*$. Considere the quaternion $Q$ defined by:


Q = \left[ \begin{matrix} a && b && c && d \end{matrix} \right]


The conjugate of $Q$ is defined by:


Q^* = \left[ \begin{matrix} a && -b && -c && -d \end{matrix} \right]


The conjugate can be used to swap the relative frames described by an orientation. For example, if ${}^BQ_A$ describes the orientation of frame $B$ relative to frame $A$, the conjugate of ${}^BQ_A^*={}^AQ_B$ and describes the orientation of frame $A$ relative to frame $B$.

# Quaternion product

The quaternion product is denoted by $\otimes$. Consider two quaternions $Q_1$ and $Q_2$ :


\begin{matrix}
Q_1 &=& \left[ \begin{matrix} a_1 && b_1 && c_1 && d_1 \end{matrix} \right] \\
Q_2 &=& \left[ \begin{matrix} a_2 && b_2 && c_2 && d_2 \end{matrix} \right]
\end{matrix}


The product is given by:

 Q_1 \otimes Q_2 =
\left[
\begin{matrix}
a_1a_2 - b_1b_2 - c_1c_2 - d_1d_2 \\
a_1b_2 + b_1a_2 + c_1d_2 - d_1c_2 \\
a_1c_2 - b_1d_2 + c_1a_2 + d_1b_2 \\
a_1d_2 + b_1c_2 - c_1b_2 + d_1a_2
\end{matrix}
\right]^\top


The quaternion product is not commutative :

 Q_1 \otimes Q_2 \neq Q_2 \otimes Q_1

# Quaternions and rotations

A quaternion is a four-dimensional complex number that can be used to represent the orientation of a ridged body or coordinate frame in three-dimensional space. The general definition of a quaternion is given by:

 Q=a+b.i+c.j+d.k = \left[
\begin{matrix}
a && b && c  && d
\end{matrix}
\right]

## Representation

Let's consider a vector $\vec{V}$ defined by 3 scalars ($V_x$, $V_y$ and $V_z$) and $\theta$ an angle of rotation around $\vec{V}$ :

The quaternion associated to this transformation is given by:

 Q = \left[
\begin{matrix}
cos \frac{\theta}{2} &&
-V_x.sin \frac{\theta}{2} &&
-V_y.sin \frac{\theta}{2} &&
-V_z.sin \frac{\theta}{2}
\end{matrix}
\right]


## Rotation around axes

Based on the previous formula, we can now calculate the quaternion defining a rotation around each axis:

Rotation around X

 Q_X=\left[
\begin{matrix}
cos \frac{\theta}{2} &&
-sin \frac{\theta}{2} &&
0 &&
0
\end{matrix}
\right]


Rotation around Y

 Q_Y=\left[
\begin{matrix}
cos \frac{\theta}{2} &&
0 &&
-sin \frac{\theta}{2} &&
0
\end{matrix}
\right]


Rotation around Z

 Q_Z=\left[
\begin{matrix}
cos \frac{\theta}{2} &&
0 &&
0 &&
-sin \frac{\theta}{2}
\end{matrix}
\right]


## General rotation

A three dimensional vector (or point) can be rotated by a quaternion using the following relationship based on the quaternion product and quaternion conjugate:

 V_B = {}^BQ_A \otimes V_A \otimes {}^BQ_A^*

$V_A$ and $V_B$ are the quaternions associated to vectors $\vec{v_A}$ and $\vec{v_B}$. Each quaternion contains a 0 inserted as the first element (rotation angle) to make them 4 element row quaternions, the other elements are given by the vector coordinates.

$\vec{v_A}$ and $\vec{v_B}$ is the same vector described in frame $A$ and frame $B$ respectively.

## Example

This simple example shows the rotation of an ellipse defined in the plane {$\vec{X}$,$\vec{Y}$}:

This example is based on the Madgwick's quaternion library for Matlab:

# Extended Kalman filter (EKF)

This post details the Kalman filter equations.

## Predict

State prediction:

 \hat{x}_{i}^p = f(\hat{x}_{i-1},u_i)

Where:

• $\hat{x}_i^p$ is the predicted state at time step $i$.
• $\hat{x}_{i}$ is the estimate of state at time step $i$.
• $f$ is differential function that describes how the state will change according to the previous state (prediction) and the system input ($u_i$).
• $u_i$ is the system input at time step $i$.

Uncertainty (or covariance) prediction:

 P_i^p = F_i.P_{i-1}.F_i^\top + Q_i

Where:

• $P_i^p$ is the error covariance matrix predicted at time step $i$.
• $P_i$ is the estimated error covariance matrix associated with the estimated state $\hat{x}_{i}$.
• $Q_i$ is the system noise covariance matrix.
• $F_i$ is the transition matrix. It is given by the Jacobian of $f()=\frac{df}{dx}$

## Update

Innovation or measurement residual:

 \widetilde{y}_i = z_i - h(\hat{x}_i^p)

Where:

• $\widetilde{y}_i$ is a measurement error : this is the difference between the measurement $z_i$ and the estimate measurement from state $\hat{x}_i^p$.
• $z_i$ is an observation (or measurement) from the true state $x_i$.
• $h$ is a differential function which maps the state space into the observed space.

Innovation (or residual) covariance:

 S_i=H_i.P_i^p.H_i^\top+R_i

Where:

• $S_i$ is the covariance matrix associated to the measurement error $\widetilde{y}_i$.
• $R_i$ is the covariance matrix for the measurement noise.
• $H_i$ is a transition matrix which maps the state space into the observed space. It is given by $H_i=\frac{dh}{dx}$

Near-optimal Kalman gain:

 K_i=P_i^p.H_i^\top.S_i^{-1}

Where

• $K_i$ is the Kalman gain, this matrix contains the balance between prediction and observations. This matrix will weight the merging between predicted state and observations.

Updated state estimate:

 \hat{x}_i=\hat{x}_i^p + K_i.\widetilde{y}_i

Updated estimate covariance

 P_i=(I-K_i.H_i).P_i^p

Where:

• $I$ is the identity matrix.

# Kalman filter

This post details the Kalman filter equations.

## Predict

State prediction:

 \hat{x}_{i}^p = F_i.\hat{x}_{i-1} + B_i.u_i

Where:

• $\hat{x}_i^p$ is the predicted state at time step $i$.
• $\hat{x}_{i}$ is the estimate of state at time step $i$.
• $F_i$ is the transition matrix. It describes how the state will change according to the previous state (prediction).
• $B_i$ is a matrix that translates control input at time step $i$ into a predicted change in state. In another words, it maps an input vector $u_i$ into the state space.
• $u_i$ is the system input at time step $i$.

Uncertainty (or covariance) prediction:

 P_i^p = F_i.P_{i-1}.F_i^\top + Q_i

Where:

• $P_i^p$ is the error covariance matrix predicted at time step $i$.
• $P_i$ is the estimated error covariance matrix associated with the estimated state $\hat{x}_{i}$.
• $Q_i$ is the system noise covariance matrix.

## Update

Innovation or measurement residual:

 \widetilde{y}_i = z_i - H_i.\hat{x}_i^p

Where:

• $\widetilde{y}_i$ is a measurement error : this is the difference between the measurement $z_i$ and the estimate measurement from state $\hat{x}_i^p$.
• $z_i$ is an observation (or measurement) from the true state $x_i$.
• $H_i$ is a transition matrix which maps the state space into the observed space.

Innovation (or residual) covariance:

 S_i=H_i.P_i^p.H_i^\top+R_i

Where:

• $S_i$ is the covariance matrix associated to the measurement error $\widetilde{y}_i$.
• $R_i$ is the covariance matrix for the measurement noise.

Optimal Kalman gain

 K_i=P_i^p.H_i^\top.S_i^{-1}

Where

• $K_i$ is the Kalman gain, this matrix contains the balance between prediction and observations. This matrix will weight the merging between predicted state and observations.

Updated state estimate:

 \hat{x}_i=\hat{x}_i^p + K_i.\widetilde{y}_i

Updated estimate covariance

 P_i=(I-K_i.H_i).P_i^p

Where:

• $I$ is the identity matrix.

# Kalman filter example

The Kalman filter is a very useful mathematical tool for merging multi-sensor data. We'll consider a very simple example for understanding how the filter works. Let's consider a robot that move in a single direction in front of a wall. Assume that the robot is equipped with two sensors : a speed measurement sensor and a distance measurement sensor (range finder). We'll consider in the following that both sensors are noisy.

Our goal is to estimate, as accurately as possible, the position $x$ of the robot:

Input of the system are a noisy distance measurement and a noisy velocity measurement:

## Source code

close all;
clear all;
clc;

% Step time
dt=0.1;
% Variance of the range finder
SensorStd=0.08;
% Variance of the speed measurement
SpeedStd=0.5;

%% Compute the robot trajectory and simulate sensors
% Time
t=[0:dt:10];
n=size(t,2)
% Trajectory
x=0.05*t.*cos(2*t);
% Accelerometer
u=[0,diff(x)/dt] + SpeedStd*randn(1,n);
% Range finder
z=x-SensorStd*randn(1,n);

% Display position
figure;
plot (t,x);
grid on;
xlabel ('Time [s]');
ylabel ('Position [m]');
title ('Robot real position versus time x=f(t)');

% Display accelation
figure;
plot (t,u,'m');
grid on;
hold on;
plot (t,[0,diff(x)/dt]+3*SpeedStd,'k-.');
plot (t,[0,diff(x)/dt]-3*SpeedStd,'k-.');
xlabel ('Time [s]');
ylabel ('Velocity [m/s]');
title ('Velocity versus time u=f(t)');

% Display range finder
figure;
plot (t,z,'r');
grid on;
hold on;
plot (t,x+3*SensorStd,'k-.');
plot (t,x-3*SensorStd,'k-.');
xlabel ('Time [s]');
ylabel ('Distance [m]');
title ('Distance versus time z=f(t)');

%% Kalman

B=dt;
F=1;
Q=SpeedStd^2;
H=1;
R=SensorStd^2;

x_hat=[0];
y_hat=[0];
P=[0];
S=[0];

for i=2:n

%% Prediction

%State
x_hat(i)=F*x_hat(i-1) + B*u(i-1);

% State uncertainty
P(i)=F*P(i-1)*F' + Q;

%% Update

% Innovation or measurement residual
y_hat(i)=z(i)-H*x_hat(i);

% Innovation (or residual) covariance
S=H*P(i)*H'+R;

K=P(i)*H'*S;

x_hat(i)=x_hat(i)+K*y_hat(i);

P(i)=(1-K*H)*P(i);
end

figure;
plot (t,x,'k');
hold on;
plot (t,x_hat);
plot (t,x_hat+sqrt(P),'r-.');
plot (t,x_hat-sqrt(P),'r-.');
legend('Real position','Estimated position','Uncertainty');

grid on;
xlabel ('Time [s]');
ylabel ('Distance [m]');
title ('Estimated position (speed only)');


This example has been inspired by the very good tutorial of Bradley Hiebert-Treuer "An Introduction to Robot SLAM (Simultaneous Localization And Mapping)"

# Normal distribution

The normal (or Gaussian) distribution is a stochastic model commonly used for estimating sensor uncertainty. The law is given by:

Where:

• $\sigma$ is the standard deviation (square root of the variance)
• $c$ is the center of the gaussian

variance=\sigma^2

Here are some examples of normal distributions:

As the sum of probabilities must be equal to one thus the following surface is equal to one:

68, 95 and 99.7% of the surface is included in respectively $\sigma$, $2.\sigma$ and $3.\sigma$:

# OpenGL and Qt-Creator

This post is a simple example of an OpenGL widget display in a Qt window. This example has been programmed with the following software versions:

• Xubuntu 14.04 LTS
• Qt Creator 3.0.1
• Qt 5.2.1 (GCC 4.8.2, 64 bit)

## Screenshot

This application display a 3-axis frame and a cube made of points:

## Software installation

You may need to install the OpenGL Utility Toolkit (GLUT):

sudo apt-get install freeglut3 freeglut3-dev

# MPU-9250 and Arduino (9-Axis IMU)

This post presents a simple example of how to interface the MPU-9250 with an Arduino board. The breakout board used here is the IMU 9DOF - MPU9250 breakout board manufactured by Drotek.

The MPU-9250 is a multi-chip module (MCM) consisting of:

• 3-Axis accelerometer
• 3-Axis gyroscope
• 3-Axis magnetometer

## Wiring

### Source code

#include

#define    GYRO_FULL_SCALE_250_DPS    0x00
#define    GYRO_FULL_SCALE_500_DPS    0x08
#define    GYRO_FULL_SCALE_1000_DPS   0x10
#define    GYRO_FULL_SCALE_2000_DPS   0x18

#define    ACC_FULL_SCALE_2_G        0x00
#define    ACC_FULL_SCALE_4_G        0x08
#define    ACC_FULL_SCALE_8_G        0x10
#define    ACC_FULL_SCALE_16_G       0x18

// Put read bytes starting at register Register in the Data array.
{
Wire.write(Register);
Wire.endTransmission();

uint8_t index=0;
while (Wire.available())
}

// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}

// Initializations
void setup()
{
// Arduino initializations
Wire.begin();
Serial.begin(115200);

// Configure gyroscope range
// Configure accelerometers range
// Set by pass mode for the magnetometers

// Request first magnetometer single measurement

}

long int cpt=0;
// Main loop, read and display data
void loop()
{

// _______________
// ::: Counter :::

// Display data counter
Serial.print (cpt++,DEC);
Serial.print ("\t");

// ____________________________________
// :::  accelerometer and gyroscope :::

uint8_t Buf[14];

// Create 16 bits values from 8 bits data

// Accelerometer
int16_t ax=-(Buf[0]<<8 | Buf[1]);
int16_t ay=-(Buf[2]<<8 | Buf[3]);
int16_t az=Buf[4]<<8 | Buf[5];

// Gyroscope
int16_t gx=-(Buf[8]<<8 | Buf[9]);
int16_t gy=-(Buf[10]<<8 | Buf[11]);
int16_t gz=Buf[12]<<8 | Buf[13];

// Display values

// Accelerometer
Serial.print (ax,DEC);
Serial.print ("\t");
Serial.print (ay,DEC);
Serial.print ("\t");
Serial.print (az,DEC);
Serial.print ("\t");

// Gyroscope
Serial.print (gx,DEC);
Serial.print ("\t");
Serial.print (gy,DEC);
Serial.print ("\t");
Serial.print (gz,DEC);
Serial.print ("\t");

// _____________________
// :::  Magnetometer :::

// Read register Status 1 and wait for the DRDY: Data Ready

uint8_t ST1;
do
{
}
while (!(ST1&0x01));

uint8_t Mag[7];

// Create 16 bits values from 8 bits data

// Magnetometer
int16_t mx=-(Mag[3]<<8 | Mag[2]);
int16_t my=-(Mag[1]<<8 | Mag[0]);
int16_t mz=-(Mag[5]<<8 | Mag[4]);

// Magnetometer
Serial.print (mx+200,DEC);
Serial.print ("\t");
Serial.print (my-70,DEC);
Serial.print ("\t");
Serial.print (mz-700,DEC);
Serial.print ("\t");

// End of line
Serial.println("");
//  delay(100);
}


### Contributors

Source code on BitBucket here.

# I2C scanner for Arduino

The following code is an I2C scanner for Arduino. It requests data from each address within the range [0:255]. I2C slaves that answer are display on the terminal.

#include

void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);

// prints title with ending line break
Serial.println("I2C scanner ::: www.lucidarme.me");
}

void loop()
{
for (int i=0;i<256;i++)
{
// Request data (read one byte)
Wire.requestFrom(i, 1);

// If slave answers, a device is found
if (Wire.available())
{
Serial.print(i,DEC);
Serial.print("\t0x");
Serial.print(i,HEX);
Serial.print("\t");
Serial.print("0b");
Serial.print(i,BIN);
Serial.print("\t");
Serial.println("Device found");
}

//    delay(100);
}
Serial.println("End of scan");
while (1);
}


# gtkmm - example 24

This is part of a more general work dedicated to gtkmm accessible here. This example shows how to create an application with Tabs. The first tab display a button and the second tab display a label.

## Source code

### main.cpp

#include
#include

int main(int argc, char* argv[])
{
// Initialize gtkmm and create the main window
Glib::RefPtr app = Gtk::Application::create(argc, argv, "www.lucidarme.me");
// Create the window
mainwindow window;
// Start main loop
return app->run(window);
}


### mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include

// The class mainwindow inherits from Gtk::Window
class mainwindow : public Gtk::Window
{
// Constructor and destructor
public:
mainwindow();
virtual             ~mainwindow();

protected:
//Signal handlers (run when the button is clicked)
void                    on_button_clicked();

//Page selector
Gtk::Notebook           Selector;

// Button for the first page
Gtk::Button             Button;

// Label for the second page
Gtk::Label              Label;
};

#endif // MAINWINDOW_H


### mainwindow.cpp

#include "mainwindow.h"

// Constructor of the main Window (build ui interface).
mainwindow::mainwindow()
{
// Resize the main window and set border width
this->resize(400,200);
set_border_width(5);

// Add the label and connect the button
Button.signal_clicked().connect(sigc::mem_fun(*this,&mainwindow::on_button_clicked));

// Set label text
Label.set_text("Page 2 (label)");

// Add the widgets (button and label) in the notebook
Selector.append_page(Button, "First");
Selector.append_page(Label, "Second");

// This packs the button into the Window (a container).
show_all_children();
}

// Destructor of the class
mainwindow::~mainwindow()
{}

// Call when the button os clicked and display my url
void mainwindow::on_button_clicked()
{
std::cout << "www.lucidarme.me" << std::endl;
}


# C++ inheritance

This post shows through a simple example how inheritance works. Let's consider a first class Parent with two member functions (fct1 and fct2). Note that fct2 is virtual. Let's now consider a second class Child (which inherit from the class Parent) that also contain two member functions (fct1 and fct2). All this functions are protected, and they can be called from outside thanks to the public member functions callFunction1 and callFunction2 that belong to the class Parent. The question is : what will happen when these functions are called from the class Child ? In the case of fct1, which is not virtual, this is the function fct1 from the class Parent that is called. On the other hand, in the case of fct2, which is virtual, this is the function belonging to the class Child that is called. Note that the parent function can be called with the following syntax: Parent::fct2(). Note also that when calling the constructor of Child, the Parent constructor is called first.
The following program illustrates this explaination:

#include

class Parent
{
public:
Parent() {std::cout << "Constructor Parent" << std::endl;}

void            callFunction1() { fct1(); }
void            callFunction2() { fct2(); }

protected:
void            fct1()
{   std::cout << "Class Parent :: function 1" << std::endl; }

virtual void    fct2()
{   std::cout << "Class Parent :: function 2" << std::endl; }
};

class Child : public Parent
{
public:
Child() {std::cout << "Constructor Child" << std::endl;}

protected:
void            fct1()
{   std::cout << "Class Child :: function 1" << std::endl; }

void            fct2()
{   std::cout << "Class Child :: function 2" << std::endl;
Parent::fct2(); }
};

int main()
{

Child c;
c.callFunction1();
c.callFunction2();
return 0;
}


This code output the following lines. The parent constructor is called before the child constructor. For fct1, this is the parent function called. For fct2, this is the child function called because the parent function is virtual.

Constructor Parent
Constructor Child
Class Parent :: function 1
Class Child :: function 2
Class Parent :: function 2


# Mute and unmute keyboard shortcut under Xubuntu or Xfce

In Setting Manager, select Keyboard and Application Shortcuts. Add the new following item:

amixer -D pulse set Master Playback Switch toggle

and press the shortcut key when requested.

# gtkmm - example 23

This is part of a more general work dedicated to gtkmm accessible here. This example shows how to display an image (Pixbuf) into a cairo drawing area. The image can be moved, scaled, fitted or centered with the mouse. Scale is done with the scroll button of the mouse. Move is controlled with the left button. The right button display a popup menu with several options as illustrated below.

## Source code

### main.cpp

#include
#include

int main(int argc, char* argv[])
{
// Initialize gtkmm and create the main window
Glib::RefPtr app = Gtk::Application::create(argc, argv, "www.lucidarme.me");
Gtk::Window window;

// Create the drawing and add an image from file
ScrollImage Img;
Img.set_image_from_file("gtk.png");

// Insert the drawing in the window
// Resize the window
window.resize(600,400);
// Set the window title
window.set_title("ScrollImage");
// Show the drawing
Img.show();

// Start main loop
return app->run(window);
}


### scrollimage.h

#ifndef SCROLLIMAGE_H
#define SCROLLIMAGE_H

#include
#include

// Minimun scale (low boundary)
#define			MIN_SCALE			0.05

class ScrollImage : public Gtk::DrawingArea
{
public:

/*!
* \brief ScrollImage				Constructor, initialize the widget.
*/
ScrollImage();

/*!
* \brief set_image_from_file		Load the image to display.
* \param filename					File name of the image.
*/
void set_image_from_file(const std::string& filename);

protected:

/*!
* \brief on_draw					Override the draw handler : update display.
*									Don't call this function to update display, call queue_draw().
* \param cr						Cairo context.
* \return							Always false.
*/
virtual bool on_draw(const Cairo::RefPtr& cr);

/*!
* \brief displayTarget				Display a little target at coordinates x,y.
* \param cr						Cairo context.
* \param x							x-coordinate of the center of the target.
* \param y							y-coordinate of the center of the target.
*/
void displayTarget(const Cairo::RefPtr& cr,double x, double y);

/*!
* \brief on_scroll_event			This function is called when the mouse scroll changes.
*									This is a default handler for the signal signal_scroll_event().
* \param event						Properties of the event.
* \return							Always true (the event is processed).
*/
bool on_scroll_event(GdkEventScroll *event);

/*!
* \brief on_button_press_event		This function is called when a mouse button is pressed.
*									This is a default handler for the signal signal_button_press_event().
* \param event						Properties of the event.
* \return							True if the event is processed, false otherwise.
*/
bool on_button_press_event(GdkEventButton *event);

/*!
* \brief on_button_release_event	This function is called when a mouse button is released
*									This is a default handler for the signal signal_button_release_event().
* \param event						Properties of the event.
* \return							True if the event is processed, false otherwise.
*/
bool on_button_release_event(GdkEventButton *event);

/*!
* \brief on_motion_notify_event	This function is called when the pointer is moved
*									This is a default handler for the signal signal_motion_notify_event().
* \param event						Properties of the event.
* \return							True if the event is processed, false otherwise.
*/
bool on_motion_notify_event(GdkEventMotion*event);

protected:
/*!
* \brief resetView					Reset the view (best image fit in the window).
* \param winWidth					Width of the window (in pixels).
* \param winHeight					Height of the window (in pixels).
* \param imgWidth					Width of the image (in pixels).
* \param imgHeight					Height of the image (in pixels).
*/
void                        fitImage(int winWidth,int winHeight, int imgWidth, int imgHeight);

/*!
* \brief fit						Set the fit flag to one and update display
*									Next call of on_draw will fit the image according to the drawing area.
*/
void                        fit();

/*!
* \brief reset						Reset display (center the image and set scale to 1:1) and update display
*/
void                        reset();

/*!
* \brief resetScale				Set scale to 1:1 and update display
*/
void                        resetScale();

/*!
* \brief setCenter					Center the image on the pointer position from last click
*/
void                        setCenter();

/*!
* \brief showHideTarget			Show or hide the center target and update display
*/
void                        showHideTarget();

private:

// Image to display
Glib::RefPtr   image;

// Scale of the image
double                      scale;

// Coordinates of the image point to place at the center of the window (focussed pixel)
double                      imgFocusX,imgFocusY;

// Used to memorize last mouse coordinates
int                         lastXMouse, lastYMouse;

// Flags
bool                        resetFlag;
bool                        moveFlag;
bool                        targetFlag;

};

#endif // SCROLLIMAGE_H


### scrollimage.cpp

#include "scrollimage.h"

// Constructor
ScrollImage::ScrollImage()
{
// Set masks for mouse events

// ::: Create popup menu :::

// Add and connect action set pointer as center

// Add and connect action Fit image to drawing area

// Add and connect action reset (center and set scale to 1)

// Add and connect action reset scale to 1

// Add and connect action reset scale to 1

// Connect the menu to this Widget

// ::: Initialize view and flags :::
fit();
moveFlag=false;
targetFlag=true;
}

// Load an image from file
void ScrollImage::set_image_from_file(const std::string& filename)
{
image = Gdk::Pixbuf::create_from_file(filename);
}

// Mouse wheel event detected : update scale
bool ScrollImage::on_scroll_event(GdkEventScroll *event)
{
// Compute the new scale according to mouse scroll
double newScale=scale*(1-event->delta_y/20);
if (newScalex - get_allocated_width()/2.;
double DeltaY=event->y - get_allocated_height()/2.;
imgFocusX=imgFocusX + DeltaX/scale - DeltaX/newScale ;
imgFocusY=imgFocusY + DeltaY/scale - DeltaY/newScale ;;

// Update scale and redraw the widget
scale=newScale;
queue_draw();

// Event has been handled
return true;
}

// Mouse button pressed : process mouse button event
bool ScrollImage::on_button_press_event(GdkEventButton *event)
{

// Check if the event is a left button click.
if (event->button == 1)
{
// Memorize pointer position
lastXMouse=event->x;
lastYMouse=event->y;
// Start moving the view
moveFlag=true;
// Event has been handled
return true;
}

// Check if the event is a right button click.
if(event->button == 3)
{
// Memorize mouse coordinates
lastXMouse=event->x;
lastYMouse=event->y;
// The event has been handled.
return true;
}
// Event has not been handled
return false;
}

// Mouse button released : process mouse button event
bool ScrollImage::on_button_release_event(GdkEventButton *event)
{
// Check if it is the left button
if (event->button==1 && moveFlag)
{
// End of motion
moveFlag=false;
// Update image focus
imgFocusX -= (event->x-lastXMouse)/scale;
imgFocusY -= (event->y-lastYMouse)/scale;
// Update display
queue_draw();
return true;
}
// Event has been handled
return false;
}

// Mouse pointer moved : process event
bool ScrollImage::on_motion_notify_event (GdkEventMotion*event)
{

// If the left button is pressed, move the view
if (moveFlag)
{
// Get mouse coordinates
int XMouse=event->x;
int YMouse=event->y;

// Update image focus
imgFocusX -= (XMouse-lastXMouse)/scale;
imgFocusY -= (YMouse-lastYMouse)/scale;

// Memorize new position of the pointer
lastXMouse=XMouse;
lastYMouse=YMouse;

// Update view
queue_draw();
return true;
}
// Event has been handled
return false;
}

// Reset view (scale is set to 1:1 and image is centered)
void ScrollImage::reset()
{
// Set scale to 1:1
scale=1;
// Update image focus
imgFocusX = image->get_width()/2.;
imgFocusY = image->get_height()/2.;
// Update display
queue_draw();
}

// Reset scale to 1:1
void ScrollImage::resetScale()
{
scale=1;
// Update display
queue_draw();
}

// Center the dispay at the pointer coordinates
void ScrollImage::setCenter()
{
// Update image focus
imgFocusX += (lastXMouse - get_allocated_width()/2.)/scale;
imgFocusY += (lastYMouse - get_allocated_height()/2.)/scale;
// Update display
queue_draw();
}

// Best fit of the image in the display
void ScrollImage::fit()
{
// Set reset flag to true, next call of on_draw will reset display
resetFlag=true;
queue_draw();
}

// Hide or show the target center
void ScrollImage::showHideTarget()
{
// Invert flag
targetFlag=!targetFlag;
// Update popup menu according to current status
if (targetFlag)
else
// Update display
queue_draw();
}

// Reset view to fit in the drawing area
void ScrollImage::fitImage(int winWidth,int winHeight, int imgWidth, int imgHeight)
{
// Compute ratio of the window and the image
double winRatio=(double)winWidth/winHeight;
double imgRatio=(double)imgWidth/imgHeight;

// Check what is the best fit for the image according to the ratio
if (imgRatio& cr)
{

// Get the window size
int winWidth=get_allocated_width();
int winHeight=get_allocated_height();

// Get the image size
int imgWidth=image->get_width();
int imgHeight=image->get_height();

// If requested, reset view
if (resetFlag) fitImage(winWidth,winHeight,imgWidth,imgHeight);

// Create a new image for display filled with grey
Glib::RefPtr display = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,false,8,winWidth,winHeight);
display->fill(0x5F5F5F00);

// Compute offset of the source image
double OffsetX=winWidth/2-imgFocusX*scale;
double OffsetY=winHeight/2-imgFocusY*scale;
// Compute top left coordinate of the image in the area
double Min_X=std::max(0.,OffsetX);
double Min_Y=std::max(0.,OffsetY);
// Compute bottom right coordinates of the image in the area
double Max_X=std::min((double)winWidth,winWidth/2+(imgWidth-imgFocusX)*scale);
double Max_Y=std::min((double)winHeight,winHeight/2+(imgHeight-imgFocusY)*scale);
// Compute width and height
double Width=Max_X-Min_X;
double Height=Max_Y-Min_Y;

// Scale image
image->scale(display,
Min_X,Min_Y,
Width,Height,
OffsetX,OffsetY,
scale,scale,Gdk::INTERP_TILES);

// Display the image in the drawing area
Gdk::Cairo::set_source_pixbuf(cr,display,0,0);
cr->rectangle(0,0,winWidth,winHeight);
cr->fill();

// Display the center target if requested
if (targetFlag) displayTarget(cr,winWidth/2.,winHeight/2.);

// Event has been handled
return false;
}

// Display a target at coordinates x,y
void ScrollImage::displayTarget(const Cairo::RefPtr& cr,double x, double y)
{
// Set color to black
cr->set_source_rgba(0,0,0,0.5);

// Display black quaters
cr->arc(x,y,15,0,M_PI/2.);
cr->line_to(x,y);
cr->fill();
cr->arc(x,y,15,M_PI,3.*M_PI/2.);
cr->line_to(x,y);
cr->fill();

// Set color to white
cr->set_source_rgba(1,1,1,0.5);

// Display white quaters
cr->arc(x,y,15,M_PI/2.,M_PI);
cr->line_to(x,y);
cr->fill();
cr->arc(x,y,15,3.*M_PI/2.,0);
cr->line_to(x,y);
cr->fill();

// Set color to black
cr->set_source_rgba(0,0,0,0.8);

// Display the cross
cr->move_to(x-20,y);
cr->line_to(x+20,y);
cr->stroke();
cr->move_to(x,y-20);
cr->line_to(x,y+20);
cr->stroke();

// Display the circle
cr->arc(x,y,15,0,2*M_PI);
cr->stroke();
}


# gtkmm - example 22

This is part of a more general work dedicated to gtkmm accessible here. This example explains and shows how to resize an image with gtkmm. Let's have a look at the Gdk::Pixbuf::scale function:

void Gdk::Pixbuf::scale	(
const Glib::RefPtr< Gdk::Pixbuf >& dest,
int 		dest_x,
int 		dest_y,
int 		dest_width,
int 		dest_height,
double 		offset_x,
double 		offset_y,
double 		scale_x,
double 		scale_y,
InterpType 	interp_type
) const


• dest is the destination image buffer (Gdk::Pixbuf). The function scales and copies the image in a new one (dest). Memory is not automatically allocated for the destination buffer. It means that the image dest must be created previously to the call of Gdk::Pixbuf::scale. Width and height of dest must be in accordance with the other arguments of the function.
• dest_x and dest_y are the coordinates of the top left point in the destination image. All the pixels on the left side of dest_x and on the upper side of dest_y will remain unchanged.
• dest_width and dest_height are the size (width and height) of the area to update in the destination buffer.
• offset_x and offset_y are the offset of the source image in the destination image's frame.
• scale_x and scale_y are the scale factor applied to the source image before the copy. A scale factor of 1 will keep the original image size. A scale factor of 2 will create an image twice the original and so one.
• interp_type is the interpolation type used for the transformation. Four types can be used :

• Gdk::INTERP_NEAREST (top left): nearest neighbor sampling; this is the fastest and lowest quality mode. Quality is normally unacceptable when scaling down, but may be OK when scaling up.
• Gdk::INTERP_TILES (bottom right): this is an accurate simulation of the PostScript image operator without any interpolation enabled. Each pixel is rendered as a tiny parallelogram of solid color, the edges of which are implemented with antialiasing. It resembles nearest neighbor for enlargement, and bilinear for reduction.
• Gdk::INTERP_BILINEAR (bottom left): Best quality/speed balance; use this mode by default. Bilinear interpolation. For enlargement, it is equivalent to point-sampling the ideal bilinear-interpolated image. For reduction, it is equivalent to laying down small tiles and integrating over the coverage area.
• Gdk::INTERP_HYPER (top right): This is the slowest and highest quality reconstruction function. It is derived from the hyperbolic filters in Wolberg's "Digital Image Warping", and is formally defined as the hyperbolic-filter sampling the ideal hyperbolic-filter interpolated image (the filter is designed to be idempotent for 1:1 pixel mapping).

## Source code

### main.cpp

#include
#include

// Scale used for the demonstration
#define         SCALE           8.

int main(int argc, char* argv[])
{
// Initialize gtkmm library
Glib::RefPtr app = Gtk::Application::create(argc, argv, "www.lucidarme.me");

Glib::RefPtr image = Gdk::Pixbuf::create_from_file("gtk_icon.png");
int width=image->get_width();
int height=image->get_height();
//image2=image; // = image->scale_simple(image->get_width()*scale,image->get_height()*scale,Gdk::INTERP_NEAREST);

// __________________________
// ::: Create output1.png :::

// Create, fill and save the destination image
Glib::RefPtr image2 = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,width*SCALE,height*SCALE);
image2->fill(0x0000FFA0);
image2->save("output1.png","png");
std::cout << "output1.png created" << std::endl;

// __________________________
// ::: Create output2.png :::

// Scale and copy the first image in the destination image with several type of scalin method
// Top left
image->scale(image2,
10,10,
(width*SCALE)/2.-10,(height*SCALE)/2-10,
0,0,
SCALE,SCALE,
Gdk::INTERP_NEAREST);
// Top right
image->scale(image2,
(width*SCALE)/2.+10,10,
(width*SCALE)/2.-20,(height*SCALE)/2.-10,
0,0,
SCALE,SCALE,
Gdk::INTERP_HYPER);
// Bottom left
image->scale(image2,
10,(height*SCALE)/2.+10,
(width*SCALE)/2.-10,(height*SCALE)/2.-20,
0,0,
SCALE,SCALE,
Gdk::INTERP_BILINEAR);
// Bottom right
image->scale(image2,
(width*SCALE)/2.+10,(height*SCALE)/2.+10,
(width*SCALE)/2.-20,(height*SCALE)/2.-20,
0,0,
SCALE,SCALE,
Gdk::INTERP_TILES);
// Save the output image
image2->save("output2.png","png");
std::cout << "output2.png created" << std::endl;

// __________________________
// ::: Create output3.png :::

// Scale and translate the source image
image2->fill(0x70707070);
image->scale(image2,
20,20,
width*SCALE-40,height*SCALE-40,
-width*SCALE/2.,-height*SCALE/2.,
SCALE*2,SCALE*2,
Gdk::INTERP_BILINEAR);
image2->save("output3.png","png");
std::cout << "output3.png created" << std::endl;

// __________________________
// ::: Create output4.png :::

// Scale and translate the source image
image2->fill(0x70707070);
image->scale(image2,
image2->get_width()/2.,image2->get_height()/2.,
image2->get_width()/2.,image2->get_height()/2.,
-width*SCALE,-height*SCALE,
SCALE*2,SCALE*2,
Gdk::INTERP_TILES);
image2->save("output4.png","png");
std::cout << "output4.png created" << std::endl;
return 0;
}