Getting Out of Comfort Zones and Train Our Brains: Deep Learning in Python and Beyond

1. Background

When I first interviewed for a new job many years ago, I had been taught from interview books that we should be able to pick up any developing tools for our programming tasks at hands. This was supposed to be my ‘standard’ answer to my interviewers. The books even mention that I shall tell my prospective employers that I was very comfort in switching among different programming languages when needed. However, the universal truth is that once we got our feet into the door of a company and have been doing our jobs for a couple of years, we tend to stay in our comfort zones created by our company culture and jobs, forgetting our interview answers in the past. The danger, as I see it, is that we had canned our skill set in the comfort zone to such an extent that our daily programming work soon becomes a boring routine.  Always keeping a healthy curiosity towards new ways of achieving the same goals is definitely great in training our brains and does us good in long term. Getting out of our comfort zones is vital to our continued success in professional career.

As a senior software developer, I have been working on Windows platform for many years and made contributions to quite a few important software projects using IDE versions ranging from Microsoft Visual Studio 2008 (WinCE), 2010 (C++), 2012 (C++, C#) and 2015 (C# WPF with Microsoft SQL connections), releasing software to and supporting customers in European countries from US headquarter and those across different local branches offices in US.

In my long professional journey working in different companies, historically I witnessed some legacy software projects whose source code was written and organized under a surprisingly huge procedural umbrella, the very old-school ways of doing the jobs back in old days. It is horrible, if not impossible, to make any change to the source code, giving another bittering fact that they had evolved over many years and were written by generations of different developers. It is really a pain in ass. Thanks to the technical advances, we now have OOP (Object-Oriented Programming) and countless design patterns in programming world out there at our disposal for our tasks and doing them beautifully. All these are showcased in our new projects now

2. Neural Networks and Deep Learning

Back in July of 2015, I came cross this video link implementing a Neural Network in C++:

Neural Net in C++ Tutorial

and was fascinated by its strong OOP approaches in laying out the source code in classes. I spent some time on brushing up my Mathematical knowledge learned back in college for a better understanding of its algorithms. I even tested it on the then-brand-new platform Window 8 and contacted David Miller, the video author, for my install experience and test results as well as comments via emails. After this interesting incident, I kept on googling for new blogs and videos as good as that of David Miller’s, and the results were quite disappointed.

Then suddenly to me in early 2017, Machine Learning (ML) and Deep Learning (DL) in Python caught my eye balls. Surprisingly it took me less than 10 minutes to set up a working Python Environment for ML and DL with Anaconda distribution on both Window 10 and 8 computers according to this blog:

How to Setup a Python Environment for Machine Learning and Deep Learning with Anaconda

As a Windows frog sitting at the bottom of its wall built around my comport zone, I saw how easily it is to install important Python distribution packages for ML and DL on Windows, such as  Anaconda, Conda, Scipy, Numpy, Matplotlib, Pandas, Statsmodels, Scikit-Learn, Theano, Tensorflow, Keras, Sympy and Pytest.

Under the Anaconda command prompt, you simply type the followings:

conda update anaconda
conda update conda
conda update scipy
conda update numpy
conda update matplotlib
conda update pandas
conda update statsmodels
conda update scikit-learn
conda update theano

These are the commands to install the packages for the first time:

pip install tensorflow
pip install keras
pip install sympy
pip install pytest

Updating an existing Python package is very easy. Last week, I was reminded that there was a new version of Spyder IDE for updating. I simply typed in Anaconda command prompt:

conda update spyder

voila, both Anconda and Spyder were updated in less than 5 minutes.

3. Install SQLAlchemy Package (for My Coming Blog)

Since I also developed software connecting to Microsoft SQL databases in the past, I keep keen eyes on Python’s way of connecting to databases and spotted SQLAlchemy package. To install it, I simple downloaded the Windows Installer from:

SQLAlchemy 1.2.0b2

and run the following command to install it:

C:\users\currentUserName\AppData\Local\Continuum\Anaconda3\Python.exe .\setup.py install

I really like the idea in SQLAlchemy of mapping a database table to a Python class, and columns to its attributes, establish relationships among different tables, as in illustrated in its ‘Object Relational Tutorial’ at:

Object Relational Tutorial

I am going to write a short blog on implement SQL Join for two database tables for a solid example to illustrate the important idea of SQLAlchemy package. Please stay tuned.

4. Proof: I Am Not a Fake Software Developer

So far, I have piled up so many words in this blog without showing any code to my readers, which does not quite sound like what a programmer usually does in a professional blog. Well, let me quickly show a short Python program plotting a Sin(x) figure, save it on my computer and insert it into this blog. I used Pylab package, which is part of the Matplotlib, and Spyder IDE that comes with the Anaconda distribution. The Python code is as follows:

import pylab
import math

def PlotSinFigure():
    xcords = [i * 0.1 for i in range(100)]
    ycords = [math.sin(x) for x in xcords]
    pylab.plot(xcords, ycords, "-o", label="sin(x)")
    pylab.legend()
    pylab.xlabel('x')
    pylab.savefig('C:\\temp\\SinWave.png')
    return
if __name__ == "__main__":
    PlotSinFigure()

The resulted sin(x) figure saved on my computer as a png file looks like the followings:

SinWave

5. A Final Short Note on ML,  DL and Their Mathematical Foundations

I have kept keen interest in ML, DL and beyond. From my experience, it is particularly amazing that with less than one hundred lines of Python code, you can quickly build a multi-layer, deep or flat or whatever-you-call-it neural network, playing with it, testing ideas of even the most recently published papers, last or even this year. Amazing ! The beauty is that you can change the network parameters to see whether your network works the way as these scholar papers claimed, or as you projects need it to be.

A final short note on mathematical foundations before building any great Neural Networks for ML and DL: I found that understanding mathematical foundations on which ML and DL have been evolved over recent years is of uttermost importance before writing any code. My favorite mathematical material, which benefited me a lot in my journal and out of my comfort zone, is the ‘Stanford Machine Learning Notes’ published on this web page:

Stanford Machine Learning

It excels by providing many vivid drawings and diagrams explaining even the most abstract and complex concepts of mathematics, how and when they apply to every problem they solve. Please do check it out and train your brain whenever you are puzzled or got lost mathematically in your long journey of ML and DL.

Posted in Deep Learning | Tagged , , , , , | Leave a comment

C++ Programming For High Performance: Pushing to Its Limit With A Case Analysis

This blog is based on the issue I identified from production code, which could seriously affect code efficiency, especially for high performance C++ code. When I looked at, I have to say we as C++ programmers finished our work at different levels of quality. Some of our work is left much to be desired. Take a trace program, for example.

class Trace {
public:
Trace(const string& s) : funcName( s ) {
if (TraceIsActive) {
cout << "Enter " << funcName << endl;
}
}
~Trace( ) {
if (TraceIsActive)  {
cout << "Leaving " << funcName << endl;
}
}
static  bool  TraceIsActive;
private:
std::string  funcName;
};

What was wrong with it? When TraceIsActive is false (trace is turned off),  funcName is still constructed, a price we do not want to pay.

Well, how about this “improvement”?

class Trace {
public:
Trace( const char* pName ) : pFuncName( 0 ) {
if ( TraceIsActive ) {
pFuncName = new string(pName);
cout << "Enter " << *pFuncName << endl;
}
}
~Trace( ) {
if (TraceIsActive) {
cout << "Leaving " << *pFuncName << endl;
delete pFuncName;
}
}
static bool TraceIsActive;
private:
string* pFuncName;
};

Good, no string is constructed unless TraceIsActive is true. Setting a pointer to 0 in the constructor is a cheap operation. Most programmers will go with this solution.

However, a static flag (TraceIsActive) is used and two if statements is tested. More problems … to be analyzed

Well, one more try:

#ifdef TRACE_ON
class Trace
{
public:
Trace(const char* name) : fileName(name) {
std::cout << "Entering " << fileName << " function" << std::endl;
}
~Trace()  {
std::cout << "Leaving " << fileName << " function " << std::endl;
}
private:
std::string fileName;
};
#else
class Trace
{
public:
Trace(const char* name ) { }
};
#endif

Good, when trace is turned off, the constructor does nothing. What a good solution! Hold on, is it?

Pushing to the limit: when trace is turned off, a Trace object is still constructed and its destructor still get called in typical use of Trace. Imagining that we have used this Trace class in one million functions in our release production code, like so:

void Foo( ) { Trace t("Foo"); }

This implies that one million Trace objects will be constructed and destructed without a single use of them when the trace is turned off in our release distribution.  What a price we are still paying!

My final solution is to use Singleton design pattern (a Singleton class template)  in such a way that only one instance of Trace is constructed and get destructed when trace is turned off, even the Trace has been used in one million functions/places in our application. I worked out my solution, but would reserve from posting its source code here. You may do it as a good C++ programming exercise yourself. The analysis of the issue and the idea to a better solution are the most important!

Posted in C++ High Performance Programming | Leave a comment

Compile Boost 1_50_0 on Windows XP for Visual Studio 2008

Boost is my favorite, cross-platform library for C++ programming. I have followed its development for the past years and am an active mailing list member of its forum. I write this post for helping those who are afraid of “messing things up” by mistakes.

Well, if you really do not want to take any risk, you may download a Boost Installer program from boostpro.com and just run it (that is all) from the following link:

http://www.boostpro.com/download/

However, as of this writing, you can only install up to boost 1_47_0.

If you want to try out all of the most recent features of boos C++ library, you may compile all boost modules via the following steps:

(0) download “boost_1_50_0.zip” from
http://sourceforge.net/projects/boost/files/boost/1.50.0/
and unzip it to (your preferred directory, in my case):
C:\boost_1_50_0

(1) Launch Visual Studio 2008 Prompt Console Windows from:

Start->All Programs->Microsoft Visual Studio 2008->Visual Studio Tools->Visual Studio Command Prompt

(2) cd C:\boost_1_50_0

(3) bootstrap.bat
This will automatically generate b2.exe under C:\boost_1_50_0 directory

(4) .\b2

At the end of this step I got the following, NICE reminding prompts:
The Boost C++ Libraries were successfully built!
The following directory should be added to compiler include paths:
C:/boost_1_50_0
The following directory should be added to linker library paths:
C:\boost_1_50_0\stage\lib

The building process is surprisingly simple and user-friendly.

Posted in Boost 1_50_0 compile for Windows, Boost C++ Compilation | Leave a comment

Interaction for 360-degree view of the teapot

A Spinning TeapotOpenGL provides excellent features for rendering 3D 360-Degree View of the Teapotgraphics. The screen shot on the left shows a spinning teapot with OpenGL (although we can not see it spinning from the screen shot). It is nice to view it that way. However, users might want to explore the teapot as they wish by actively choosing which part of the teapot to look at, giving them more control and interaction in the process. The next two screen shots shows a Graphic User Interface (GUI) that makes it possible to view the teapot from 360 degrees by changing its x, y and z axis. In addition, the user can also left-click and move the mouse to rotate the teapot around x and y axis, right-click and move the mouse to rotate the teapot around x and z axis. When the mouse key is used for interaction, the sliders involved would automatically update themselves.

The Qt project file *.pro file is as follows:

TARGET = 4_teapot
TEMPLATE = app
SOURCES += main.cpp \
window.cpp \
glwidget.cpp
HEADERS += window.h \
glwidget.h
QT += opengl

The glwidget.cpp file is as follows:

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>

class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);

QSize minimumSize() const;
QSize sizeHint() const;

public slots:
void setXRotation(int angle);
void setYRotation(int angle);
void setZRotation(int angle);

signals:
void xRotationChanged(int angle);
void yRotationChanged(int angle);
void zRotationChanged(int angle);

protected:
void initializeGL();
void paintGL();
void resizeGL(int w, int h);
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);

private:
int xRot;
int yRot;
int zRot;
QPoint lastPos;
};

#endif // GLWIDGET_H
Posted in Qt for 3D Graphic User Interfaces | Leave a comment

Making A 3D Graphic User Interface Using Qt OpenGL Widgets

So far every widget in our interface displays a 2D object. How about making a 3D graphic user interface and exploring different dimensions of 3D objects in it? Sounds like a good idea, doesn’t it? Let us start with building such an interface.

In this Qt project, we are going to modify the interface we built in my last blog (link:https://zhaowuluo.wordpress.com/2011/06/22/interacting-with-openglwidgets/). We are going to replace the top-left corner widget originally showing the National Flag of US with a QGLWidget showing a 3D object, namely a Qt logo, together with three sliders for us to rotate it in x, y and z directions. You may download source code for this Qt project from this link (https://rcpt.yousendit.com/1211085777/25c7f0903e92d59b73bcd31fa65b8b2d).The screen shot of this interface is shown as follows:

A 3D Graphic User Interface With QGLWidget for User Interaction

1. Description of the Interface

The Qt project file, 3DGUI.pro, is as follows:

3DGUI.pro

TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
QT += opengl

# Input
HEADERS += circlebar.h \
circlebarwindow.h \
glwidget.h \
helper.h \
logoglwidget.h \
logowindow.h \
qtlogo.h \
renderarea.h \
widget.h \
window.h
SOURCES += circlebar.cpp \
circlebarwindow.cpp \
glwidget.cpp \
helper.cpp \
logoglwidget.cpp \
logowindow.cpp \
main.cpp \
qtlogo.cpp \
renderarea.cpp \
widget.cpp \
window.cpp

We are going to use three classes for the above-mentioned widget: LOGOGLWidget class declared in logoglwidget.h and implemented in logoglwidget.cpp file, LOGOWindow class declared in logowindow.h and implemented in logowindow.cpp and QtLogo class declared in qtlogo.h and implemented in qtlog.cpp. You may find source code of these files and explanation of their functions in Qt documentation. The head files look as follows:

logoglwidget.h

#ifndef LOGOGLWIDGET_H
#define LOGOGLWIDGET_H

#include <QGLWidget>

class QtLogo;

class LOGOGLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit LOGOGLWidget(QWidget *parent = 0);
~LOGOGLWidget();

QSize minimumSizeHint() const;
QSize sizeHint() const;

public slots:
void setXRotation(int angle);
void setYRotation(int angle);
void setZRotation(int angle);

signals:
void xRotationChanged(int angle);
void yRotationChanged(int angle);
void zRotationChanged(int angle);

protected:
void initializeGL();
void paintGL();
void resizeGL(int w, int h);
void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);

private:
QtLogo *logo;
int xRot;
int yRot;
int zRot;
QPoint lastPos;
QColor qtGreen;
QColor qtPurple;
};

#endif // LOGOGLWIDGET_H

logowindow.h

#ifndef LOGOWINDOW_H
#define LOGOWINDOW_H

#include <QtGui/QWidget>

class QSlider;
class LOGOGLWidget;

class LOGOWindow : public QWidget
{
Q_OBJECT

public:
LOGOWindow();

protected:
void keyPressEvent(QKeyEvent *);

private:
QSlider *createSlider();

LOGOGLWidget *glWidget;
QSlider  *xSlider;
QSlider  *ySlider;
QSlider  *zSlider;
};

#endif // LOGOWINDOW_H

qtlogo.h

#ifndef QTLOGO_H
#define QTLOGO_H

#include <QObject>
#include <QtOpenGL>

class Geometry;
class Patch;

class QtLogo : public QObject
{
public:
QtLogo(QObject *parent, int d = 64, qreal s = 1.0);;
~QtLogo();

void setColor(QColor c);
void draw() const;

private:
void buildGeometry(int d, qreal s);

QList<Patch *> parts;
Geometry *geom;
};

#endif // QTLOGO_H

 

2. Implementing the widget in our interface

First, we need to add the include directive in the window.cpp file of the Qt project mentioned above (with a link to it). In its constructor, we need create an instance of LOGOWindow object and lay it out in our interface with the QGridLayout::addWidget() method. That is all to it. The following source code shown the minor modifications we have to make to the window.cpp file:

window.cpp (modification part only)

#include "logowindow.h"

Window::Window() : helper(Helper() )
{
LOGOWindow *logowin = new LOGOWindow;
QLabel *logowinLabel = new QLabel(tr("3D OpenGL Widget (X, Y, Z Rotations)"));
logowinLabel->setAlignment( Qt::AlignHCenter);

// ...

QGridLayout *layout = new QGridLayout(this);
layout->addWidget(logowin, 0, 0);
layout->addWidget(logowinLabel, 1, 0 );
// ...
}
Posted in Qt for 3D Graphic User Interfaces | Leave a comment

Interacting with Qt GUI Interface with OpenGL and Native Qt Widgets

1. Introduction

It would be nice if we can interact directly with widgets in our GUI interfaces. Let us start with a simple Qt GUI interface that we can interact with. Its screen shot is as follows:


A Qt GUI Interface with 2 OpenGL widgets (top row, left two) and other native Qt widgets

You may download source code for this Qt project from this link: http://www.yousendit.com/download/MFo3TkFsT010Ni92Wmc9PQ

2. A Brief Description of the Qt Project

To begin with, let us take a look at its Qt project file and get an idea of C++ source code files in it:

Demo.pro

QT += opengl
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .

# Input
HEADERS += circlebar.h \
circlebarwindow.h \
flagwidget.h \
glwidget.h \
helper.h \
renderarea.h \
widget.h \
window.h
SOURCES += circlebar.cpp \
circlebarwindow.cpp \
flagwidget.cpp \
glwidget.cpp \
helper.cpp \
main.cpp \
renderarea.cpp \
widget.cpp \
window.cpp

The US national flag is rendered with OpenGL code in class FlagWidget defined in flagwidget.h and implemented in flagwidget.cpp.

flagwidget.h

#ifndef FLAGWIDGET_H
#define FLAGWIDGET_H

#include <QGLWidget>

class FlagWidget : public QGLWidget
{
Q_OBJECT
public:
explicit FlagWidget(QWidget *parent = 0);

protected:
void initializeGL();
void resizeGL(int width, int height);
void paintGL();

private:
void drawStar(float fX, float fY);
void drawStars();
void drawStripes();
};

#endif // FLAGWIDGET_H

As can be seen in the following implementation file, two private methods, FlagWidget::drawStars() and FlagWidget::drawStripes, are directly called in FlagWidget::paintGL() method. The FlagWidget::drawStars() method then calls the third private method, FlagWidget::drawStar(). These private methods implement our algorithm to draw the flag with OpenGL code. They are private so that we can easily switch from one implementation/algorithm of today to anther in the future without changing on its interface. Our clients can happily continue using new implementation/algorithm without noticing our change, a nice object-oriented feature of C++ encapsulation. Please note that the US flag must have a width/height ratio of 1.9, which is enforced on line 8 of the following cpp file:

flagwidget.cpp

#include "flagwidget.h"
#include <math.h>

FlagWidget::FlagWidget(QWidget *parent) :
QGLWidget(parent)
{
// flag ratio (W/H) must be 1.9
setFixedSize( 418, 220 );
}

void FlagWidget::initializeGL()
{
glClearColor(0.0, 0.0, 102.0/255.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

void FlagWidget::resizeGL(int width, int height)
{
glViewport(0, 0, (GLint)width, (GLint)height);
}

void FlagWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
drawStripes();
drawStars();
glFlush();
}

void FlagWidget::drawStar(float fX, float fY)
{
const float kfPi = 3.1415926535897932384626433832795;
const float kfRadius = 0.0616/2.0;
const float kfInnerRadius = kfRadius*(1.0/(sin((2.0*kfPi)/5.0)*2.0*cos(kfPi/10.0) + sin((3.0*kfPi)/10.0)));
glColor3f(1.0, 1.0, 1.0);

glBegin(GL_TRIANGLE_FAN);
glVertex3f(fX, fY, 0.0);
for (int iVertIndex = 0; iVertIndex < 10; ++iVertIndex)
{
float fAngleStart    = kfPi/2.0 + (iVertIndex*2.0*kfPi)/10.0;
float fAngleEnd        = fAngleStart + kfPi/5.0;
if (iVertIndex % 2 == 0)
{
glVertex3f(fX + kfRadius*cos(fAngleStart)/1.9, fY + kfRadius*sin(fAngleStart), 0.0);
glVertex3f(fX + kfInnerRadius*cos(fAngleEnd)/1.9, fY + kfInnerRadius*sin(fAngleEnd), 0.0);
} else
{
glVertex3f(fX + kfInnerRadius*cos(fAngleStart)/1.9, fY + kfInnerRadius*sin(fAngleStart), 0.0);
glVertex3f(fX + kfRadius*cos(fAngleEnd)/1.9, fY + kfRadius*sin(fAngleEnd), 0.0);
}
}
glEnd();
}

void FlagWidget::drawStars()
{
for (int iStarRow = 0; iStarRow < 9; ++iStarRow)
{
float fY = 6.0/13.0 + (iStarRow + 1)*((7.0/13.0)/10);
if (iStarRow % 2 == 0)
{
for (int iStarCol = 0; iStarCol < 6; ++iStarCol)
drawStar(iStarCol*((0.76/1.9)/6.0) + (0.76/1.9)/12.0, fY);
} else {
for (int iStarCol = 0; iStarCol < 5; ++iStarCol)
drawStar((iStarCol + 1)*((0.76/1.9)/6.0), fY);
}
}
}

void FlagWidget::drawStripes()
{
for (int iStripeIndex = 0; iStripeIndex < 13; ++iStripeIndex)
{
if (iStripeIndex % 2 == 0)
glColor3f(204.0/255.0, 0.0, 0.0);
else
glColor3f(1.0, 1.0, 1.0);

float fStartX    = 0.0;
float fEndX    = 1.0;
float fStartY    = iStripeIndex*(1.0/13.0);
float fEndY    = (iStripeIndex + 1)*(1.0/13.0);

if (iStripeIndex > 5)
fStartX = 0.76/1.9;

glBegin(GL_QUADS);
glVertex3f(fStartX, fStartY, 0.0);
glVertex3f(fEndX, fStartY, 0.0);
glVertex3f(fEndX, fEndY, 0.0);
glVertex3f(fStartX, fEndY, 0.0);
glEnd();
}
}

The OpenGL Widget is defined in glwidget.h and implemented in glwidget.cpp. The Native Qt Widget is defined in widget.h and implemented in widget.cpp. They both use the Helper class declared in helper.h and implemented in helper.cpp for painting after setting up the content for the QPainter. The  QTimer is used to create the animation effect. I included source code for these three classes from Qt documentation.

There is no visual difference between the two widgets. However, on systems with hardware acceleration, the OpenGL widget should have obvious performance improvement over the native Qt widget.

glwidget.h

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>

class Helper;
class QPaintEvent;
class QWidget;

class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(Helper *helper, QWidget *parent = 0);

public slots:
void animate();

protected:
void paintEvent(QPaintEvent *event);

private:
Helper *helper;
int elapsed;
};

#endif // GLWIDGET_H

glwidget.cpp

#include <QtGui>
#include "glwidget.h"
#include "helper.h"

GLWidget::GLWidget(Helper *helper, QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent), helper(helper)
{
elapsed = 0;
setFixedSize(220, 220);
setAutoFillBackground(false);
}

void GLWidget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
repaint();
}

void GLWidget::paintEvent(QPaintEvent *event) {
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Helper;
class QPaintEvent;

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(Helper* helper, QWidget *parent = 0);

public slots:
void animate();

protected:
void paintEvent(QPaintEvent *event);

private:
Helper *helper;
int elapsed;
};

#endif // WIDGET_H

widget.cpp


#include <QtGui>
#include "helper.h"
#include "widget.h"

Widget::Widget(Helper* helper, QWidget *parent)
:QWidget(parent), helper(helper)
{
elapsed = 0;
setFixedSize(220, 220);
}

void Widget::animate()
{
elapsed = (elapsed + qobject_cast<QTimer*>(sender())->interval()) % 1000;
repaint();
}

void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
helper->paint(&painter, event, elapsed);
painter.end();
}


helper.h

#ifndef HELPER_H
#define HELPER_H

#include <QBrush>
#include <QFont>
#include <QPen>

class QPainter;
class QPaintEvent;

class Helper
{
public:
Helper();

public:
void paint(QPainter *painter, QPaintEvent *event, int elapsed);

private:
QBrush background;
QBrush circleBrush;
QPen circlePen;
QFont textFont;
QPen textPen;
};

#endif // HELPER_H

helper.cpp

#include <QPainter>
#include <QPaintEvent>
#include "helper.h"

Helper::Helper()
{
QLinearGradient gradient(QPointF(50, 20), QPointF(80, 20));
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));

background  = QBrush(QColor(64, 32, 64));
circleBrush = QBrush(gradient);
circlePen = QPen(Qt::black);
circlePen.setWidth(1);;
textPen = QPen(Qt::white);
textFont.setPixelSize(50);
}

void Helper::paint(QPainter *painter, QPaintEvent *event, int elapsed)
{
painter->fillRect(event->rect(), background);
painter->translate(100, 100);

painter->save();
painter->setBrush(circleBrush);
painter->setPen(circlePen);
painter->rotate(elapsed * 0.020);

qreal r = elapsed/1000.0;
int n = 30;
for (int i = 0; i <  n; ++i) {
painter->rotate(30);;
qreal radius = 0 + 120*((i+r)/n);
qreal circuleRadius = 1 + ((i+r)/n)*20;
painter->drawEllipse(QRectF(radius, -circuleRadius,
circuleRadius*2, circuleRadius*2));
}
painter->restore();

painter->setPen(textPen);
painter->setFont(textFont);
painter->drawText(QRectF(-50, -50, 100, 100), Qt::AlignCenter, "Qt");
}

The top, right widget, in the form of CircleBar class, is defined in circlebar.h and implemented in circlebar.cpp. In order to put a horizontal slider under it and lay them out in our interface, the class CircleBarWindow is declared in circlebarwindow.h and implemented in circlebarwindow.cpp. The outer, black, circle is drawn when the interface is up. The user can change the diameter of the inner circle (drawn like a red rose) by moving the slider. The diameter of the rose in pixel is automatically updated and shown below the slider. Alternatively, the user can move the mouse into the outer, black, circle and use mouse wheel to change its diameter.

circlebar.h

#ifndef CIRCLEBAR_H
#define CIRCLEBAR_H

#include <QWidget>

class CircleBar : public QWidget
{
Q_OBJECT

public:
CircleBar(int value = 0, QWidget *parent = 0);
int value() const;
int heightForWidth(int) const;

protected slots:
void setValue(int);

signals:
void valueChanged(int);

protected:
void paintEvent(QPaintEvent *);
void wheelEvent(QWheelEvent *);

private:
int m_value;
};

#endif // CIRCLEBAR_H

circlebar.cpp


#include <QPaintEvent>
#include <QWheelEvent>
#include <QPainter>
#include <QRadialGradient>

#include "circlebar.h"

CircleBar::CircleBar(int value, QWidget *parent)
: QWidget(parent)
{
m_value = value;

QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred);
policy.setHeightForWidth( true );
setSizePolicy( policy );
}

int CircleBar::heightForWidth(int width) const
{
return width;
}

int CircleBar::value() const
{
return m_value;
}

void CircleBar::setValue(int value)
{
if (value < 0 )
value = 0;

if (value > 100)
value = 100;

if (m_value == value)
return;

m_value = value;
update();
emit valueChanged(m_value);
}

void CircleBar::paintEvent(QPaintEvent *)
{
int radius = width()/2;
double factor = m_value/100.0;

QPainter painter( this );
painter.setPen(Qt::black );
painter.drawEllipse(0, 0, width()-1, width()-1);

QRadialGradient radGrad( QPointF(radius, radius), 10 );
radGrad.setColorAt( 0, Qt::red );
radGrad.setColorAt( 1, Qt::white );
radGrad.setSpread( QGradient::RepeatSpread );
painter.setPen(Qt::white );
painter.setBrush( radGrad );
painter.drawEllipse( int(radius*(1.0-factor)), int(radius*(1.0-factor)),
int((width()-1)*factor)+1, int((width()-1)*factor)+1 );
}

void CircleBar::wheelEvent(QWheelEvent *event)
{
event->accept();
setValue( value() + event->delta()/20 );
}

circlebarwindow.h

#ifndef CIRCLEBARWINDOW_H
#define CIRCLEBARWINDOW_H

#include <QWidget>
#include <QSlider>

class CircleBarWindow : public QWidget
{
Q_OBJECT
public:
explicit CircleBarWindow(QWidget *parent = 0);

// getter to encapsulate the private QSlider *slider;
const QSlider *getSliderPtr() const;

private:
QSlider *slider;

};

#endif // CIRCLEBARWINDOW_H

circlebarwindow.cpp


#include <QLabel>
#include <QGridLayout>

#include "circlebarwindow.h"
#include "circlebar.h"

CircleBarWindow::CircleBarWindow(QWidget *parent) :
QWidget(parent)
{
CircleBar *bar = new CircleBar(0, this);
slider = new QSlider(Qt::Horizontal, this);
QGridLayout *layout = new QGridLayout(this);
layout->addWidget( bar, 0, 0, 2, 2);
layout->addWidget( slider, 5, 0, 1, 1);

connect( slider, SIGNAL(valueChanged(int)), bar, SLOT(setValue(int)) );
connect( bar, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)) );
}

const QSlider *CircleBarWindow::getSliderPtr() const
{
return slider;
}

Please note that I declared the “const QSlider *getSliderPtr() const" on line 14 of the circlebarwindow.h and implemented it on lines 20 to 23 of the circlebarwindow.cpp file. This is how I strive to prevent users from messing up with the naked pointer (QSlider *slider). It would be dangerous to simply declare the pointer as public and allow clients to mess it up, a trap that we can easily fall into.


The last four widgets in the second row of the screen shot use RenderArea class declared in renderarea.h and implemented in renderarea.cpp. RenderArea class defines the area for painter to paint, specify what operation to be performed on one of the shapes, draw the x and y axes in red lines, translate, scale or rotate the coordinate system, etc.

renderarea.h


#ifndef RENDERAREA_H

#define RENDERAREA_H

#include <QFont>
#include <QList>
#include <QPainterPath>
#include <QRect>
#include <QWidget>

class QPaintEvent;

enum Operation {NoTransformation, Translate, Rotate, Scale };

class RenderArea : public QWidget
{
Q_OBJECT
public:
RenderArea(QWidget *parent = 0);

void setOperations(const QList<Operation> &operations);
void setShape(const QPainterPath &shape);

QSize minimumSizeHint() const;
QSize sizeHint() const;

protected:
void paintEvent(QPaintEvent *event);

private:
void drawCoordinates(QPainter &painter);
void drawOutline(QPainter &painter);
void drawShape(QPainter &painter);
void transformPainter(QPainter &painter);

QList<Operation> operations;
QPainterPath shape;
QRect xBoundingRect;
QRect yBoundingRect;
};

#endif // RENDERAREA_H

renderarea.cpp

#include <QPainter>
#include <QPaintEvent>

#include "renderarea.h"

RenderArea::RenderArea(QWidget *parent)
: QWidget(parent)
{
QFont newFont = font();
newFont.setPixelSize(12);
setFont(newFont);
QFontMetrics fontMetrics(newFont);
xBoundingRect = fontMetrics.boundingRect(tr("x"));
yBoundingRect = fontMetrics.boundingRect(tr("y"));
}

void RenderArea::setOperations(const QList<Operation> &operations)
{
this->operations = operations;
update();
}

void RenderArea::setShape(const QPainterPath &shape)
{
this->shape = shape;
update();
}

QSize RenderArea::minimumSizeHint() const
{
return QSize(182, 182);
}

QSize RenderArea::sizeHint() const
{
return QSize(232, 232);
}

void RenderArea::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillRect(event->rect(), QBrush(Qt::white));
painter.translate(66, 66);

painter.save();
transformPainter(painter);
drawShape(painter);
painter.restore();

drawOutline(painter);
transformPainter(painter);
drawCoordinates(painter);
}

void RenderArea::drawCoordinates(QPainter &painter)
{
painter.setPen(Qt::red);
painter.drawLine(0, 0, 50, 0);
painter.drawLine(48, -2, 50, 0);
painter.drawLine(48, 2, 50, 0);
painter.drawText(60 - xBoundingRect.width()  / 2,
0 + xBoundingRect.height() / 2, tr("x"));

painter.drawLine(0, 0, 0, 50);
painter.drawLine(-2, 48, 0, 50);
painter.drawLine(2, 48, 0, 50);
painter.drawText(0 - yBoundingRect.width()  / 2,
60 + yBoundingRect.height() / 2, tr("y"));
}

void RenderArea::drawOutline(QPainter &painter)
{
painter.setPen(Qt::darkGreen);
painter.setPen(Qt::DashLine);
painter.setBrush(Qt::NoBrush);
painter.drawRect(0, 0, 100, 100);
}

void RenderArea::drawShape(QPainter &painter)
{
painter.fillPath(shape, Qt::blue);
}

void RenderArea::transformPainter(QPainter &painter)
{
for (int i = 0; i < operations.size(); ++i) {
switch (operations[i]) {
case Translate:
painter.translate(50, 50);
break;
case Scale:
painter.scale(0.75, 0.75);
break;
case Rotate:
painter.rotate(60);
break;
case NoTransformation:
default:
;
}
}
}

The four widgets in the second row of the screen short are actually created and laid out with class Window declared in in window.h and an implemented in window.cpp. So are all other widgets we saw in our interface. From the combo drop down menu, we can select either "Clock", "House", "Text" or "Truck" shape to draw, select either "No transformation", "Rotate by 60 degrees", "Scale to 75%", or "Translate by (50, 50)" operation to perform. We can see how these widgets and other ones are laid out in our interface in the following two files (I adopted code for renderearea.h, rendereare.cpp and window.h from the Book "Foundations of Qt Development" by Johan Thelin and modified its code in window.cpp for this project):

window.h

#ifndef WINDOW_H
#define WINDOW_H

#include <QList>
#include <QPainterPath>
#include <QWidget>
#include <QComboBox>
#include <QLabel>

#include "renderarea.h"
#include "helper.h"

class Window : public QWidget
{
Q_OBJECT

public:
Window();

public slots:
void operationChanged();
void shapeSelected(int index);

private:
void setupShapes();
enum { NumTransformedAreas = 3 };
QComboBox *operationComboBoxes[NumTransformedAreas];
RenderArea *transformedRenderAreas[NumTransformedAreas];
QList<QPainterPath> shapes;
RenderArea *originalRenderArea;
QComboBox *shapeComboBox;
Helper helper;
};
#endif // WINDOW_H

window.cpp

#include <QGridLayout>
#include <QTimer>

#include "window.h"
#include "glwidget.h"
#include "widget.h"
#include "flagwidget.h"
#include "circlebarwindow.h"

Window::Window() : helper(Helper() )
{
FlagWidget *flag = new FlagWidget;
QLabel *flagLabel = new QLabel(tr("US National Flag Rendered with OpenGL"));
flagLabel->setAlignment( Qt::AlignHCenter);

GLWidget *openGL = new GLWidget(&helper);
QLabel *openGLLabel = new QLabel(tr("OpenGL Widgets (Left Two)"));
openGLLabel->setAlignment((Qt::AlignHCenter));

Widget *native = new Widget(&helper);
QLabel *nativeLabel = new QLabel(tr("Native Qt Widgets (Other Six)"));
nativeLabel->setAlignment(Qt::AlignHCenter);

CircleBarWindow *barWindow =  new CircleBarWindow;
QLabel *radius = new QLabel(tr("Radius"));
QLabel *value = new QLabel(tr("0"));
QLabel *pixel = new QLabel(tr("pixels"));

originalRenderArea = new RenderArea;
shapeComboBox = new QComboBox;
shapeComboBox->addItem(tr("Clock"));
shapeComboBox->addItem(tr("House"));
shapeComboBox->addItem(tr("Text"));
shapeComboBox->addItem(tr("Truck"));

QGridLayout *layout = new QGridLayout(this);
layout->addWidget(flag, 0, 0);
layout->addWidget(flagLabel, 1, 0 );
layout->addWidget(openGL, 0, 1);
layout->addWidget(openGLLabel, 1, 1);
layout->addWidget(native, 0, 2);
layout->addWidget(nativeLabel, 1, 2);
layout->addWidget(barWindow, 0, 3 );
layout->addWidget(radius, 1, 3, 1, 1, Qt::AlignLeft);
layout->addWidget(value, 1, 3, 1, 1, Qt::AlignHCenter);
layout->addWidget(pixel, 1, 3, 1, 1, Qt::AlignRight);
layout->addWidget(originalRenderArea, 2, 0, 1, 1, Qt::AlignHCenter);
layout->addWidget(shapeComboBox, 3, 0, 1, 1, Qt::AlignHCenter);

for (int i = 0; i < NumTransformedAreas; ++i)
{
transformedRenderAreas[i] = new RenderArea;

operationComboBoxes[i] = new QComboBox;
operationComboBoxes[i]->addItem(tr("No transformation"));
operationComboBoxes[i]->addItem(tr("Rotate by 60\xB0"));
operationComboBoxes[i]->addItem(tr("Scale to 75%"));
operationComboBoxes[i]->addItem(tr("Translate by (50, 50)"));

connect(operationComboBoxes[i], SIGNAL(activated(int)),
this, SLOT(operationChanged()));

layout->addWidget(transformedRenderAreas[i], 2, i + 1);
layout->addWidget(operationComboBoxes[i], 3, i + 1);
}
setLayout(layout);

setupShapes();
shapeSelected(0);
setWindowTitle(tr("Transformations, 2D Painting on Native and OpenGL Widgets"));
setFixedSize(1100, 540);

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), native, SLOT(animate()));
connect(timer, SIGNAL(timeout()), openGL, SLOT(animate()));
connect( barWindow->getSliderPtr(), SIGNAL(valueChanged(int)), value,SLOT(setNum(int)));

timer->start(50);
}

void Window::setupShapes()
{
QPainterPath truck;
truck.setFillRule(Qt::WindingFill);
truck.moveTo(0.0, 87.0);
truck.lineTo(0.0, 60.0);
truck.lineTo(10.0, 60.0);
truck.lineTo(35.0, 35.0);
truck.lineTo(100.0, 35.0);
truck.lineTo(100.0, 87.0);
truck.lineTo(0.0, 87.0);
truck.moveTo(17.0, 60.0);
truck.lineTo(55.0, 60.0);
truck.lineTo(55.0, 40.0);
truck.lineTo(37.0, 40.0);
truck.lineTo(17.0, 60.0);
truck.addEllipse(17.0, 75.0, 25.0, 25.0);
truck.addEllipse(63.0, 75.0, 25.0, 25.0);

QPainterPath clock;
clock.addEllipse(-50.0, -50.0, 100.0, 100.0);
clock.addEllipse(-48.0, -48.0, 96.0, 96.0);
clock.moveTo(0.0, 0.0);
clock.lineTo(-2.0, -2.0);
clock.lineTo(0.0, -42.0);
clock.lineTo(2.0, -2.0);
clock.lineTo(0.0, 0.0);
clock.moveTo(0.0, 0.0);
clock.lineTo(2.732, -0.732);
clock.lineTo(24.495, 14.142);
clock.lineTo(0.732, 2.732);
clock.lineTo(0.0, 0.0);

QPainterPath house;
house.moveTo(-45.0, -20.0);
house.lineTo(0.0, -45.0);
house.lineTo(45.0, -20.0);
house.lineTo(45.0, 45.0);
house.lineTo(-45.0, 45.0);
house.lineTo(-45.0, -20.0);
house.addRect(15.0, 5.0, 20.0, 35.0);
house.addRect(-35.0, -15.0, 25.0, 25.0);

QPainterPath text;
QFont font;
font.setPixelSize(50);
QRect fontBoundingRect = QFontMetrics(font).boundingRect(tr("Qt"));
text.addText(-QPointF(fontBoundingRect.center()), font, tr("Qt"));

shapes.append(clock);
shapes.append(house);
shapes.append(text);
shapes.append(truck);

connect(shapeComboBox, SIGNAL(activated(int)),
this, SLOT(shapeSelected(int)));
}

void Window::operationChanged()
{
static const Operation operationTable[] =
{
NoTransformation, Rotate, Scale, Translate
};

QList<Operation> operations;
for (int i = 0; i < NumTransformedAreas; ++i)
{
int index = operationComboBoxes[i]->currentIndex();
operations.append(operationTable[index]);
transformedRenderAreas[i]->setOperations(operations);
}
}

void Window::shapeSelected(int index)
{
QPainterPath shape = shapes[index];
originalRenderArea->setShape(shape);
for (int i = 0; i < NumTransformedAreas; ++i)
transformedRenderAreas[i]->setShape(shape);
}

Now that everything falls into its position, it is trivial to write the main.cpp:

#include <QApplication>

#include "window.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Window window;
window.show();
return app.exec();
}
Posted in Qt for 2D graphics with OpenGL | Leave a comment

Integrating OpenGL Code into a Qt Project for 2D Rendering: Basic Concept and Approach

The national flag of US rendered with OpenGL as the result of our Qt project

1. What are we going to do in this Qt project?

Let us start with a very simple project and understand how OpenGL code should be integrated into a Qt project. The OpenGL code renders the National Flag of the United States and shows it on the screen. I am assuming that readers completely understand the OpenGL code. In this blog I am concentrating on Qt part of it.

In this project, we are going to design two C++ classes and use one main.cpp file. The first class, called “MainWidget”, is the top level widget/window that serves as the container of a QWidget (flag on the left side of the top screen shot), a QPushButton (the “Close” button on its right side) and a vertical Spencer (invisible in the screen shot, to the right of the flag and on top of the “Close” button). The other class, named “GLWidget”, is the class that the original QWidget in the form of Qt Designer is going to be “promoted” to. This is where our OpenGL code would render its content, namely, the flag on the left side of the top screen shot.

The project file is as follows:

QT += opengl
TARGET = 1_usFlag
TEMPLATE = app
SOURCES += main.cpp \
mainwidget.cpp \
glwidget.cpp
HEADERS += mainwidget.h \
glwidget.h
FORMS += mainwidget.ui

Step 1: Creating a Qt project

Open the Qt creator IDE by typing “qtcreator”  in an opened terminal. Select “File->New File or Project” to create a new Qt project. Name the project as “1_usFlag” and press “OK” button; select “Qt4 Gui Application”, press “OK” button, and tick “QtOpenGL” in addition to the default selection of “QtCore” and “QtGui”, finally press “Next” button.

In the opened window, type “MainWidget” as the Class Name, select “QWidget” as the Base class, “QObject” as the Inherited Class, both from drop down menu  and press “next” button to finish. The IDE would automatically generate “mainwidget.ui” form and the following three files for us:

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>

namespace Ui {
class MainWidget;
}

class MainWidget : public QWidget {
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();

protected:
void changeEvent(QEvent *e);

private:
Ui::MainWidget *ui;
};

#endif // MAINWIDGET_H

mainwidget.cpp

#include "mainwidget.h"
#include "ui_mainwidget.h"

MainWidget::MainWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MainWidget)
{
ui->setupUi(this);
}

MainWidget::~MainWidget()
{
delete ui;
}

void MainWidget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

main.cpp

#include <QtGui/QApplication>
#include "mainwidget.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWidget w;
w.show();
return a.exec();
}

As mentioned early, “mainwidget.h” and “mainwidget.cpp” is our top-level window in the form of a class “MainWidget” that serves as a container of other widgets. We are not going to modify any of the three files. So keep them as they are. However, we are going to work on the “mainwidget.ui” form.

If you compile the project at this point, you are going to see a window that shows nothing. So let us add things for it to display.

Step 2: Work on the form

Now double click on the “mainwidget.ui” form under the “Forms” of the project files. This will bring up the Qt Designer, then add a QPushButton, a Spencer and a QWidget to it. The layout looks like the following screen shot:

Action 1: set maximum constraint for the close button

Action 2: Connect click() signal of "Close" button to close() slot of MainWidget

In order to allow OpenGL code to have the largest area possible to render its content by default or when the window is resizing, we take Actions 1 and 2, and lay out the three items in a grid layout. After this setting up, when the window is resized, the “Close” button and the Spencer would remain the same size, only the Widget part would be resized. We also connect the clicked() signal of the “Close” button to the close() slot of the MainWidget (the top, container window) in Action 2.

Step 3: Adding GLWidget class and have QWidget on the form promoted to it

Now right click on the “1_usFlag” project name and select “Add New”, then “C++ Class”; type “GLWidget” as the Class Name, “QGLWidget” as the Base class, “QWidget” as the Inherited Class and press “next” button to finish. Now we get “glwidget.h” and glwidget.cpp”.

We are going to promote the QWidget on the form of “mainwidget.ui” to our newly added “GLWidget” class illustrated as the following screen shots:

Action 3: select "promote to" for the QWidget on the form for class promotion

Action 4: type above info, press Add and Promote buttons

Action 5: the window should looks like this

Action 5: confirm that the "QWidget" is now changed to "GLWidget" where the cursor is in this shot

Step 4: Implementing “GLWidget” class

Now that the “Widget” in the form is promoted to “GLWidget” class, we can implement this class and add OpenGL code to render the flag into it:

glwidget.h

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>

class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QWidget *parent = 0);

protected:
void initializeGL();
void resizeGL(int width, int height);
void paintGL();

private:
void drawStar(float fX, float fY);
void drawStars();
void drawStripes();
};

#endif // GLWIDGET_H

glwidget.cpp

#include <cmath>
#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent) :
QGLWidget(parent)
{
}

void GLWidget::initializeGL()
{
glClearColor(0.0, 0.0, 102.0/255.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

void GLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, (GLint)width, (GLint)height);
}

void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
drawStripes();
drawStars();
glFlush();
}

void GLWidget::drawStar(float fX, float fY)
{
const float kfPi = 3.1415926535897932384626433832795;
// draw ten triangles
const float kfRadius = 0.0616/2.0;
const float kfInnerRadius = kfRadius*(1.0/(sin((2.0*kfPi)/5.0)*2.0*cos(kfPi/10.0) + sin((3.0*kfPi)/10.0)));
glColor3f(1.0, 1.0, 1.0);

glBegin(GL_TRIANGLE_FAN);
glVertex3f(fX, fY, 0.0);
for (int iVertIndex = 0; iVertIndex < 10; ++iVertIndex)
{
float fAngleStart    = kfPi/2.0 + (iVertIndex*2.0*kfPi)/10.0;
float fAngleEnd        = fAngleStart + kfPi/5.0;
if (iVertIndex % 2 == 0)
{
glVertex3f(fX + kfRadius*cos(fAngleStart)/1.9, fY + kfRadius*sin(fAngleStart), 0.0);
glVertex3f(fX + kfInnerRadius*cos(fAngleEnd)/1.9, fY + kfInnerRadius*sin(fAngleEnd), 0.0);
} else
{
glVertex3f(fX + kfInnerRadius*cos(fAngleStart)/1.9, fY + kfInnerRadius*sin(fAngleStart), 0.0);
glVertex3f(fX + kfRadius*cos(fAngleEnd)/1.9, fY + kfRadius*sin(fAngleEnd), 0.0);
}
}
glEnd();
}

void GLWidget::drawStars()
{
for (int iStarRow = 0; iStarRow < 9; ++iStarRow)
{
float fY = 6.0/13.0 + (iStarRow + 1)*((7.0/13.0)/10);
// alternate between rows of five or six stars
if (iStarRow % 2 == 0)
{
for (int iStarCol = 0; iStarCol < 6; ++iStarCol)
{
drawStar(iStarCol*((0.76/1.9)/6.0) + (0.76/1.9)/12.0, fY);
}
} else
{
for (int iStarCol = 0; iStarCol < 5; ++iStarCol)
{
drawStar((iStarCol + 1)*((0.76/1.9)/6.0), fY);
}
}
}
}

void GLWidget::drawStripes()
{
for (int iStripeIndex = 0; iStripeIndex < 13; ++iStripeIndex)
{
// Alternate stripe colors
if (iStripeIndex % 2 == 0)
{
glColor3f(204.0/255.0, 0.0, 0.0);
} else
{
glColor3f(1.0, 1.0, 1.0);
}

float fStartX    = 0.0;
float fEndX    = 1.0;
float fStartY    = iStripeIndex*(1.0/13.0);
float fEndY    = (iStripeIndex + 1)*(1.0/13.0);

// the last seven stripes are shorter
if (iStripeIndex > 5)
{
fStartX = 0.76/1.9;
}

glBegin(GL_QUADS);
glVertex3f(fStartX, fStartY, 0.0);
glVertex3f(fEndX, fStartY, 0.0);
glVertex3f(fEndX, fEndY, 0.0);
glVertex3f(fStartX, fEndY, 0.0);
glEnd();
}
}

Compile and run it, we get the following output screen shot:

Result of our project

However, there is one more thing to improve: the national flag of US should has a ratio of 1.9 (W/H) as specified at usflag.org, we should modify the form as illustrated in the following screen shot by setting its minimum width to 950 pixels and height to 500 pixels:

Adjust aspect ration of the flag

Now compile and run our project, we get the screen shot at the top of this blog.

Posted in Qt for 2D graphics with OpenGL | Leave a comment

Qt and OpenGL for Computer Graphics and Information Visualization

My interests in Graphic User Interfaces (GUI) design and Computer Graphics with Qt and OpenGL inspire me to keep adding blogs here. With Qt, it is possible to draw advanced 2D graphics with QPainter and QGraphicsView APIs. More interesting to me, Qt has excellent support for 3D graphics through its OpenGL module such as QGLWidget. This makes it possible to integrate many beautiful 2D and 3D graphics originally designed and developed with OpenGL into Qt projects. It provides a powerful means not only for us to view 2D and 3D graphics as with OpenGL, but also for us to actively interact with them through the GUI interfaces that Qt framework is so proud of being able to achieve, opening a door to the fantastic world of information visualization. This page serves as a summary of some of my work on these topics.

1. Integrating OpenGL Code into a Qt Project for 2D Rendering: Basic Concept and Approach Please check out the following link for step-by-step details: https://zhaowuluo.wordpress.com/2011/06/09/nationalflagofunitedstates/

Screen Shot of the Qt Project Output with OpenGL Code Rendering the National Flag of US

2. Interacting with Qt GUI Interface with OpenGL and Native Qt Widgets Please check out this link for its details: https://zhaowuluo.wordpress.com/2011/06/22/interacting-with-openglwidgets/

A Qt GUI Interface with 2 OpenGL widgets (top row, left two) and other native Qt widgets

3. Making A 3D Graphic User Interface Using Qt OpenGL Widgets Please check out the following link for project details:https://zhaowuluo.wordpress.com/2011/06/23/making-a-3d-gui-with-qt-qopengl-widget/

4. Interaction for 360-degree view of the teapot Please check out the following link for project details: https://zhaowuluo.wordpress.com/2011/07/01/interaction-with-the-teapot/


Rotating the teapot around x, y and z axis with sliders

Posted in Qt for 2D graphics with OpenGL | Leave a comment

Pthread Multithreading for Matrix Multiplication on Unix/Linux

In my previous blog, I discussed Boost C++ multithreading and show a working C++ multithreading program using Boost.Thread. Its main idea for the parallel algorithm is to let each of threads working on a “slice” of shared data. The “slice” is cut with so much caution that each of the threads would never cross the border of its own data and change other part of data that the remaining threads are concurrently working on. When such a perfect “cut” is possible, each thread would not have to wait for other threads from the start to the completion of its subtask, thus no thread synchronization is needed. The identical rationale can be applied to many other tasks of this category, such as image processing (pixel manipulation) and vector calculation.

Pthread Implementation

The same idea can be implemented in Pthread multithread programs too. The following list is a working, Pthread multithreading code doing exactly the same matrix multiplication as in the previous C++ blog, although in plain, procedural C style. We could have wrapped it into a C++ class, but that is a future topic. Here it is a plain C implementation of the idea using Pthread libraries in the file “matrixMultiply.c”

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

#define SIZE 10   // Size by SIZE matrices
int num_thrd;   // number of threads

int A[SIZE][SIZE], B[SIZE][SIZE], C[SIZE][SIZE];

// initialize a matrix
void init_matrix(int m[SIZE][SIZE])
{
  int i, j, val = 0;
  for (i = 0; i < SIZE; i++)
    for (j = 0; j < SIZE; j++)
      m[i][j] = val++;
}

void print_matrix(int m[SIZE][SIZE])
{
  int i, j;
  for (i = 0; i < SIZE; i++) {
    printf("\n\t| ");
    for (j = 0; j < SIZE; j++)
      printf("%2d ", m[i][j]);
    printf("|");
  }
}

// thread function: taking "slice" as its argument
void* multiply(void* slice)
{
  int s = (int)slice;   // retrive the slice info
  int from = (s * SIZE)/num_thrd; // note that this 'slicing' works fine
  int to = ((s+1) * SIZE)/num_thrd; // even if SIZE is not divisible by num_thrd
  int i,j,k;

  printf("computing slice %d (from row %d to %d)\n", s, from, to-1);
  for (i = from; i < to; i++)
  {  
    for (j = 0; j < SIZE; j++)
    {
      C[i][j] = 0;
      for ( k = 0; k < SIZE; k++)
 C[i][j] += A[i][k]*B[k][j];
    }
  }
  printf("finished slice %d\n", s);
  return 0;
}

int main(int argc, char* argv[])
{
  pthread_t* thread;  // pointer to a group of threads
  int i;

  if (argc!=2)
  {
    printf("Usage: %s number_of_threads\n",argv[0]);
    exit(-1);
  }

  num_thrd = atoi(argv[1]);
  init_matrix(A);
  init_matrix(B);
  thread = (pthread_t*) malloc(num_thrd*sizeof(pthread_t));

  // this for loop not entered if threadd number is specified as 1
  for (i = 1; i < num_thrd; i++)
  {
    // creates each thread working on its own slice of i
    if (pthread_create (&thread[i], NULL, multiply, (void*)i) != 0 )
    {
      perror("Can't create thread");
      free(thread);
      exit(-1);
    }
  }

  // main thread works on slice 0
  // so everybody is busy
  // main thread does everything if threadd number is specified as 1
  multiply(0);

  // main thead waiting for other thread to complete
  for (i = 1; i < num_thrd; i++)
 pthread_join (thread[i], NULL);

  printf("\n\n");
  print_matrix(A);
  printf("\n\n\t       * \n");
  print_matrix(B);
  printf("\n\n\t       = \n");
  print_matrix(C);
  printf("\n\n");

  free(thread);

  return 0;

}

Compile and execute the program

cc matrixMultiply.c -o matrixMultiply -lpthread
./ matrixMultiply 4

Posted in Pthread Multithreading(2) | Leave a comment

Pthread For Multithreading

Pthread Multithreading

IEEE Pthread (POSIX thread) libraries are very popular for multithreading among Unix and Linux programmers. Contrary to Boost.Thread, Pthread libraries are C language-based. C language is also the computer language with which Unix and Linux operating systems were developed. When working with Pthread, the advantages of object-oriented features provided by such languages as C++ and Qt are gone and we have to work under the constraints of C language. Of course, we can wrap Pthread system calls into C++ classes and continue enjoying these advantages. Today, you can even have C code calls C++ code, and C++ code calls C code with Mixing Coding technique under certain conditions, an interesting topic that I would like to write about in the near future. However, before doing that, make sure you are not re-invent the wheels. In fact, Boost.Thread is a wrapper, threading library wrapping Pthread system calls under the hood. It is always a good idea to check this out so as not to waste your time.

In many situations, we have to write multithreading code in plain C language. This blog serves as a pointers to many Pthread multithreading topics in which I am interested. I am going to update this blog as each new topic is added to it.

List of Topics About Pthread Multithreading

1. Pthread Multithreading for Matrix Multiplication on Unix/Linux

2. (Under construction)

Posted in Pthread Multithreading(2) | Leave a comment