Tuesday, December 18, 2012

Python in Qt Creator

I've been recently working to port Saera to the N9, which means I have to use Qt. After a few dead ends, I decided to try building a few of the Qt sample apps to get a feel for how it was supposed to work. I learned how to use Qt Creator, how to pair with a device, and how to write a simple QML app. I decided to move on to the project itself - and ran into a large hurdle to clear: Qt Creator doesn't support Python.
Or rather, it does, but only as a filetype; there isn't a way to tell Qt Creator to use a Python file as the main executable rather than the C++ file it automatically generates. I didn't really want to have to port Saera to C, so I went searching for a workaround. It turns out there is a fork of Qt Creator with Python support; however, I couldn't get it to compile properly on my system. And Google wasn't much help; most of the results I found were basically saying "If you want to use Python, you can't have the convenience of Qt Creator, but rather you have to do the whole thing manually."
However, I found a workaround: Leave the C++ in there, but rather than having it load and run the QML, have it load the Python file itself, and just run that. For those who are interested, here's my code:

C++:
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include <libgen.h>

Q_DECL_EXPORT int main(int argc, char *argv[])
{


    enum { BUFFERSIZE = 1024 };
    char buf[BUFFERSIZE];
    ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)-1);

    if (len != -1) {
      buf[len] = '\0';
    }
    else {
      return 2;
    }

    char *dirc = strdup(buf);
    char *dname = dirname(dirc);
    strcat(dname, "/../qml/saera/main.py");

    char *arr[] = {"python", dname, NULL};
    execvp("python", arr);
}
Python code (main.py):
#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import sys, os
from PySide import QtCore
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtDeclarative import *
os.chdir(os.path.dirname(os.path.abspath(__file__)))
size = (800, 480)
app = QApplication(sys.argv)
view = QDeclarativeView()
window = QMainWindow()
window.resize(*size)
window.setCentralWidget(view)
view.setResizeMode(QDeclarativeView.SizeRootObjectToView)
view.setSource("main.qml")
window.show()
app.exec_()







Wednesday, August 15, 2012

Cyclic Physics Mapping

In computer games, the performance of a complex physical object, such as a car, is generally represented by a few numbers: in the case of a car, numbers representing acceleration, tire grip, center of gravity, drag, etc. These numbers are "tweaked" to get performance that matches the real thing, if there is a real thing being modeled. This works fine for making the perfect replica of an existing vehicle, but what about if you want to make something new? You can't just plug in numbers, because you have no numbers to plug in. So, you could guess, or you could physically model the workings of the car.
The latter would seem like a great way to get a good model. After all, if designers use CAD to predict the performance of a part in real life, why not just predict the performance of all the parts and build a virtual car? The problem is speed. Let's look at the engine itself. Inside the cylinders, a mixture of gasoline and air explodes, pushing the cylinder down. Explosions aren't cheap to simulate; and as even an idling engine produces more than 25 explosions per second, it seems impossible that one could simulate an entire running engine, much less a whole car.
Or is it? There's a great way to reduce physics computing overhead, which is known in the Bullet physics library as "sleeping". This happens when:

  1. the forces acting on an object are in equilibrium, 
  2. that object has been static for a period of time (a second or so), and
  3. there is no active object within the reaction boundaries.
To illustrate:
Two falling blocks in Blender; the white outline indicates they are active.
The blocks after coming to rest. The green indicates that they are now "sleeping" and no longer being calculated.
The problem with this is that it only works on objects which are completely at rest. How do we deal with an active object? The solution is lumping things together. For example, instead of doing a laborious fluid dynamics calculation for the explosion, we can lump the combustion chamber into a system with five variables: the amount of gas entering the chamber, the amount of air entering the chamber, the momentum of the piston, the force the piston exerts on the gas, and the speed of the piston. We can calculate the amount of gas that actually burns now, and from that deduce the temperature change (and volume change) in the gas - and therefore the force on the piston.
This is great, but it still won't come anywhere close to simulating a vehicle in real time. The solution is in seeing that most things come in some form of cycles - in this case, the piston repeats itself every two revolutions of the crankshaft. So, we can simulate this cycle once and then just repeat it until one of the variables changes.
But why re-simulate each time a variable changes? The output it creates is continuous within reasonable parameters - so why not just simulate the cycle several times, for different data points in each of the variables, and use splines to interpolate the performance in real time? Furthermore, now that we have a system with a few variable inputs and outputs, it can be lumped into a larger system. Now we can treat the engine as a whole as a system, which has a few variables: fuel input, air input, crankshaft speed, and power output. At lower revs, the crankshaft speed won't be constant, because it slows down in between each explosion, but at higher revs it would be nearly constant.
The discontinuity is the point where the engine stalls; beyond this point a cyclic simulation is pointless.
So, now we've lumped the engine into a single "black box" as seen by our physics engine, but this can continue. This lumping method, which I will call "Cyclic Physics Mapping" because we are mapping physical properties into parameterised cycles, allows us to make progressively larger "black boxes" out of components, until we have basically what was mentioned at the beginning of this post - a car whose performance is represented by a few variables - except that now we have a physical model of the entire car. Which has certain consequences: for example, it is relatively easy to redo the CPM for a different fuel, to simulate, say, nitrous injection, or a switch from gasoline to hydrogen. Also - suppose you drive over a parking bumper at high speed and bend your transmission. That's going to create more drag; the mapping down to the transmission level will have to be redone, but the engine simulation is not affected - you will now be driving a car that now behaves realistically as a damaged car would. There's not really an easy way to do that with purely numbers-based systems.
This isn't just applicable to cars; you could do the same thing for anything complex and physical in a virtual world - boats, planes, even the guns in an FPS could have a physical basis in the same way. And  even noncomplex objects, like the boxes shown before, would be handled like this - once the boxes come to rest relative to the platform they are on, they and the platform can now be treated as a group. Any system that interacts minimally with other systems can be considered a black box under these circumstances.



Saturday, April 28, 2012

Hidden methods in Python

How would one access variables programmatically in Python? Well, there are two dictionaries, one returned by globals() which contains all global variables, and one returned by locals() which contains all local variables. To demonstrate:
>>> a = 4
>>> locals()['a']
4
>>> locals()['b'] = 'spam'
>>> b
'spam'
>>>
Declaring a variable is the same thing as accessing its name in the locals() dictionary (or the globals() dictionary if the variable is declared global).
But what if we do this:
class a:
    b = 4
locals()['a.b'] = 'spam'
What will be the value of a.b?

Wednesday, March 28, 2012

Learning Python

I was cleaning out a flash drive and found the log I made two years ago when learning Python. I thought I'd post the first day here. Bear in mind that the only languages I knew beforehand were ActionScript and JavaScript.

2010/05/08 10:20: Started the Python tutorial. It's nice that you don't need to install anything extra. Hello world is simple but there are no parentheses. Interesting.

Friday, March 23, 2012

C/C++ loop surprises

A basic element of almost any program is a loop. Loops are a simple concept to grasp, but they can have pitfalls in some languages; here I will present one I learned about yesterday in C.
The basic for loop in C is of this form:
int n;
unsigned int i;
for (i=0; i<n; i++) {
    //do something
}
Which is pretty foolproof as long as you leave i alone inside the loop. But another type of loop is the decrementing loop. Here is a simple program that prints the numbers from 5 down to 1:

#include <stdio.h>


int main (int argc, char **argv) {
int n = 5;
unsigned int i;
for (i=n; i>=1; i--) {
printf("%u\n", i);
}
}
And the output:

5
4
3
2
1