I have an application with qt creator that gets geocoordinate data and shows it on the map.it works fine with just one connection but when it comes to having more than once makes it a riddle. I want to get data in a loop from several qtcp connections with different addresses and ports then put data in separated lists and after reading the list of each connection geodata add separate layers on a map in different threads which updates every 3 seconds while all of them getting data concurrently from the network packets. suppose I have many different gps receivers to gather data of their location I want to integrate it on the map. here is my code sample:
1.define list of servers that qtcp client should be connected:
globals.cpp
#define PACKET 50
struct Connects{
static QMap<QString,int> list()
{
QMap<QString,int> m;
m["sender1.com"] = 4456;
m["sender2.com"] = 4457;
m["sender3.com"] = 4458;
return m;
}
static const QMap<QString,int> myMap;
};
QMap<QString, int> const Connects::myMap = list();
2.main window to launch map:
main.cpp
void add_layer(MarbleWidget *mapWidget,MainWindow *window,Client *client,QTimer *timer ){
//get data and append to a list every 3 sec
timer = new QTimer;
QObject::connect(timer,SIGNAL(timeout()),window,SLOT(next_client()));
QObject::connect(client,SIGNAL(Client_Connected()),window,SLOT(online_slot()));
timer->start(3000);
// Add New Layer based on positions in the list
MPaintLayer* layer = new MPaintLayer(mapWidget);
for(int j = 0; j < client->data.count(); ++j){
layer->setPosition(client->data.at(j).Lat,client->data.at(j).Lon);
}
mapWidget->addLayer(layer);
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
// Load Marble
MarbleWidget *mapWidget = new MarbleWidget;
mapWidget->show();
//iterate over connections address and port list
QMapIterator<QString,int> i(Connects::myMap);
while (i.hasNext()) {
i.next();
client = new Client;
client->ConnectToServer(i.key(),i.value());
//make thread pool and create new thread for adding each layer
QThreadPool pool;
QFuture<void> tr;
tr = QtConcurrent::run(&pool,add_layer,mapWidget,this,client,timer);
}
}
void MainWindow::online_slot()
{
//fetch data from the buffer and separate each entity based on size
while (client->GetLanBufferSize() >= PACKET) {
client->ReadData((char*)buffer,PACKET);
double lat,lon;
memcpy(&lat,&buffer[8],sizeof(double));
memcpy(&lon,&buffer[16],sizeof(double));
//put buffer data to target list which is defined in client
Target trg;
client->data.append(trg);
}
//remove has-readed data
for (int var = 0; var < client->data.count(); ++var) {
client->data.removeAt(var);
var--;
}
}
3.declare class for add or update a new layer based on recieved data on the map:
paintlayer.cpp
MPaintLayer::MPaintLayer(MarbleWidget* widget)
{
S_N = QPixmap(":/mode-s.png");
}
bool MPaintLayer::render( GeoPainter *painter,ViewportParams *viewport,
const QString& renderPos, GeoSceneLayer * layer )
{
//throw a tiny png file on map based on retrieved locations
for (int var = 0; var < pos.count(); ++var) {
painter->drawPixmap(pos[var],S_N));
}
return true;
}
void MPaintLayer::setPosition(double lat,double lon)
{
pos.append(GeoDataCoordinates(lat,lon,0,GeoDataCoordinates::Degree));
}
5.define a class for the format of received data:
client.h
class Target
{
public:
Target()
{
Lat = Lon = 0;
}
double Lat,Lon;
GeoDataCoordinates Position;
void update(double lat,double lon)
{
Lat = lat;
Lon = lon;
Position = GeoDataCoordinates(Lon,Lat,0,GeoDataCoordinates::Degree);
}
};
6.declare class for making new qtcp connection and receive data:
client.cpp
Client::Client(QObject *parent) : QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),this, SLOT(on_connected()));
}
void Client::on_connected()
{
connect(socket, SIGNAL(disconnected()),this, SLOT(on_Disconnected()));
socket->setReadBufferSize(12e6);
emit Client_Connected();
}
bool Client::ReadData(char *buffer, int Leanth)
{
socket->read(buffer , Leanth);
return true;
}
int Client::GetLanBufferSize()
{
return socket->bytesAvailable();
}
void Client::on_Disconnected()
{
emit Client_DisConnected();
}
void Client::ConnectToServer(QString Address , int Port)
{
socket->connectToHost(Address, Port);
server = Address;
server_Port = Port;
}
the data format which is received from the senders is location of moving object something like this:
35.51243 51.22478
35.51260 51.22667
35.69270 51.03961
what is the best practice solution? because it shows nothing on the map. when I used hard code, it showed layers equivalent to each connection but reading stream of data is challengeable. any clue would be appreciated.