Update of /cvsroot/playerstage/code/player/server/drivers/vectormap
In directory
sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20455/server/drivers/vectormap
Added Files:
.cvsignore Makefile.am dbconn.cc dbconn.h postgis.cc
Log Message:
added vectormap interface
added postgis vectormap driver
Thanks to Ben Morelli for these changes
--- NEW FILE: .cvsignore ---
Makefile
Makefile.in
--- NEW FILE: dbconn.cc ---
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include "dbconn.h"
#ifdef HAVE_GEOS
#include <geos_c.h>
#endif
using namespace std;
bool PostgresConn::Connect(const char* dbname, const char* host, const char*
user, const char* password, const char* port)
{
conn = PQsetdbLogin(host, port, NULL, NULL, dbname, user, password);
return (PQstatus(conn) != CONNECTION_BAD);
}
bool PostgresConn::Disconnect()
{
PQfinish(conn);
conn = NULL;
//return (PQstatus(conn) == CONNECTION_BAD);
return true;
}
VectorMapInfoHolder PostgresConn::GetVectorMapInfo(vector<string> layerNames)
{
// Get the extent in the first query
string query_string = "SELECT asbinary(extent(geom)) FROM (SELECT geom FROM ";
for (uint ii=0; ii<layerNames.size(); ++ii)
{
if (ii == 0)
{
query_string += layerNames[ii];
}
else
{
query_string += " UNION SELECT geom FROM " + string(layerNames[ii]);
}
}
query_string += ") AS layer_extent;";
//PGresult* res = PQexec(conn, query_string.c_str());
PGresult* res = PQexecParams(conn,
query_string.c_str(),
0,
NULL,
NULL,
NULL,
NULL,
1);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
cout << "Error performing select query on database!" << endl;
cout << "No extent value found." << endl;
cout << "GetVectorMapInfo() failed" << endl;
}
uint8_t* wkb_temp = reinterpret_cast<uint8_t*>(PQgetvalue(res, 0, 0));
uint length = PQgetlength(res, 0, 0);
uint8_t* wkb = new uint8_t[length];
memcpy(wkb, wkb_temp, length);
BoundingBox extent = BinaryToBBox(wkb, length);
delete[] wkb;
// Get the srid in the second query
res = PQexec(conn, "SELECT srid FROM geometry_columns LIMIT 1;");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
cout << "Error performing select query on database!" << endl;
cout << "No srid value found." << endl;
cout << "GetVectorMapInfo() failed" << endl;
}
uint32_t srid = atoi(PQgetvalue(res, 0, 0));
PQclear(res);
VectorMapInfoHolder info(srid, extent);
for (uint i=0; i<layerNames.size(); ++i)
{
LayerInfoHolder layer_info(layerNames[i]);
LayerDataHolder layer_data(layer_info);
info.layers.push_back(layer_data);
}
return info;
}
LayerInfoHolder PostgresConn::GetLayerInfo(const char* layer_name)
{
LayerInfoHolder info;
// Retrieve the extent of the layer in binary form
const char* query_template = "SELECT asbinary(extent(geom)) AS extent FROM
%s;";
char query_string[MAX_PSQL_STRING];
memset(query_string, 0, MAX_PSQL_STRING);
snprintf(query_string, MAX_PSQL_STRING, query_template, layer_name);
//PGresult* res = PQexec(conn, query_string);
PGresult* res = PQexecParams(conn,
query_string,
0,
NULL,
NULL,
NULL,
NULL,
1);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
cout << "Error performing select query on database!" << endl;
cout << "GetLayerInfo() failed" << endl;
}
info.name = layer_name;
uint length = PQgetlength(res, 0, 0);
uint8_t* wkb = new uint8_t[length];
memcpy(wkb, PQgetvalue(res, 0, 0), length);
info.extent = BinaryToBBox(wkb, length);
PQclear(res);
return info;
}
LayerDataHolder PostgresConn::GetLayerData(const char* layer_name)
{
// Split into two queries. First get the layer meta-data, then get the
feature data.
// need to get layer name count, layer name, feature count and exteny
LayerDataHolder data;
data.info.name = layer_name;
// need to get name count, name, wkb count, wkb
const char* template_data = "SELECT name, asbinary(geom) FROM %s;";
char query_data[MAX_PSQL_STRING];
memset(query_data, 0, sizeof(MAX_PSQL_STRING));
snprintf(query_data, MAX_PSQL_STRING, template_data, layer_name);
//res = PQexec(conn, query_data);
PGresult* res = PQexecParams(conn,
query_data,
0,
NULL,
NULL,
NULL,
NULL,
1);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
cout << "Error performing select query on database!" << endl;
cout << "GetLayerData() data failed, returned NULL" << endl;
}
int num_rows = PQntuples(res);
for (int i=0; i<num_rows; ++i)
{
FeatureDataHolder fd(string(PQgetvalue(res, i, 0)));
uint8_t *wkb = reinterpret_cast<uint8_t *>(PQgetvalue(res, i, 1));
uint32_t length = PQgetlength(res, i, 1);
fd.wkb.assign(wkb, &wkb[length]);
data.features.push_back(fd);
}
PQclear(res);
return data;
}
BoundingBox PostgresConn::BinaryToBBox(const uint8_t* wkb, uint length)
{
BoundingBox res;
memset(&res, 0, sizeof(BoundingBox));
#ifdef HAVE_GEOS
GEOSGeom polygon = NULL;
polygon = GEOSGeomFromWKB_buf(wkb, length);
if (polygon == NULL)
{
printf("GEOSGeomFromWKB_buf returned NULL!\n");
return res;
}
GEOSGeom linestring = GEOSGetExteriorRing(polygon);
if (linestring == NULL)
{
printf("GEOSGetExteriorRing returned NULL!\n");
return res;
}
GEOSCoordSeq coords = GEOSGeom_getCoordSeq(linestring);
if (coords == NULL)
{
printf("GEOSGeom_getCoordSeq returned NULL!\n");
return res;
}
double xmin = INT_MAX, ymin = INT_MAX;
double xmax = INT_MIN, ymax = INT_MIN;
double tempX, tempY = 0;
for (int ii=0; ii<GEOSGetNumCoordinates(linestring); ++ii)
{
GEOSCoordSeq_getX(coords, ii, &tempX);
GEOSCoordSeq_getY(coords, ii, &tempY);
if (tempX > xmax)
xmax = tempX;
if (tempX < xmin)
xmin = tempX;
if (tempY > ymax)
ymax = tempY;
if (tempY < ymin)
ymin = tempY;
}
res.x0 = xmin;
res.y0 = ymin;
res.x1 = xmax;
res.y1 = ymax;
#endif
return res;
}
const player_vectormap_info_t* VectorMapInfoHolder::Convert()
{
info.srid = srid;
info.extent.x0 = extent.x0;
info.extent.y0 = extent.y0;
info.extent.x1 = extent.x1;
info.extent.y1 = extent.y1;
info.layers_count = layers.size();
info.layers = new player_vectormap_layer_data_t[layers.size()];
for (uint ii=0; ii<layers.size(); ++ii)
{
info.layers[ii] = *(layers[ii].Convert());
}
return &info;
}
VectorMapInfoHolder::~VectorMapInfoHolder()
{
// if (info.layers)
// {
// delete[] info.layers;
// }
}
const player_vectormap_layer_info_t* LayerInfoHolder::Convert()
{
layer_info.name = strdup(name.c_str());
layer_info.name_count = name.size() + 1;
layer_info.extent.x0 = extent.x0;
layer_info.extent.y0 = extent.y0;
layer_info.extent.x1 = extent.x1;
layer_info.extent.y1 = extent.y1;
return &layer_info;
}
const player_vectormap_feature_data_t* FeatureDataHolder::Convert()
{
feature_data.name = strdup(name.c_str());
feature_data.name_count = name.size() + 1;
feature_data.wkb = new uint8_t[wkb.size()];
feature_data.wkb_count = wkb.size();
///TODO: Make more efficient
for (uint ii=0; ii<wkb.size(); ++ii)
{
feature_data.wkb[ii] = wkb[ii];
}
return &feature_data;
}
FeatureDataHolder::~FeatureDataHolder()
{
// if (feature_data.wkb)
// {
// delete[] feature_data.wkb;
// }
}
const player_vectormap_layer_data_t* LayerDataHolder::Convert()
{
layer_data.info = *(info.Convert());
layer_data.features_count = features.size();
layer_data.features = new player_vectormap_feature_data_t[features.size()];
for (uint ii=0; ii<features.size(); ++ii)
{
layer_data.features[ii] = *(features[ii].Convert());
}
return &layer_data;
}
LayerDataHolder::~LayerDataHolder()
{
// if (layer_data.features)
// {
// delete[] layer_data.features;
// }
}
--- NEW FILE: dbconn.h ---
#ifndef __DBCONN_H_
#define __DBCONN_H_
#include <postgresql/libpq-fe.h>
#include <libplayercore/playercore.h>
#include <libplayercore/error.h>
#include <vector>
#define MAX_PSQL_STRING 256
using namespace std;
typedef struct
{
double x0, y0, x1, y1;
}BoundingBox;
class FeatureDataHolder
{
public:
FeatureDataHolder(){};
~FeatureDataHolder();
FeatureDataHolder(string name)
{
this->name = name;
};
const player_vectormap_feature_data_t* Convert();
string name;
vector<uint8_t> wkb;
player_vectormap_feature_data_t feature_data;
};
class LayerInfoHolder
{
public:
LayerInfoHolder(){};
LayerInfoHolder(string name)
{
this->name = name;
memset(&extent, 0, sizeof(extent));
};
const player_vectormap_layer_info_t* Convert();
string name;
BoundingBox extent;
player_vectormap_layer_info_t layer_info;
};
class LayerDataHolder
{
public:
LayerDataHolder(){};
~LayerDataHolder();
LayerDataHolder(LayerInfoHolder info)
{
this->info = info;
};
const player_vectormap_layer_data_t* Convert();
LayerInfoHolder info;
vector<FeatureDataHolder> features;
player_vectormap_layer_data_t layer_data;
};
class VectorMapInfoHolder
{
public:
VectorMapInfoHolder(){};
~VectorMapInfoHolder();
VectorMapInfoHolder(uint32_t srid, BoundingBox extent) { this->srid = srid;
this->extent = extent; };
const player_vectormap_info_t* Convert();
uint32_t srid;
vector<LayerDataHolder> layers;
BoundingBox extent;
player_vectormap_info_t info;
};
class PostgresConn
{
public:
PostgresConn(){ conn = NULL; };
~PostgresConn(){ if (Connected()) Disconnect(); };
bool Connect(const char* dbname, const char* host, const char* user, const
char* password, const char* port);
bool Disconnect();
bool Connected() { return (conn != NULL) && (PQstatus(conn) !=
CONNECTION_BAD); };
const char* ErrorMessage() { return strdup(PQerrorMessage(conn)); };
VectorMapInfoHolder GetVectorMapInfo(vector<string> layerNames);
LayerInfoHolder GetLayerInfo(const char *layer_name);
LayerDataHolder GetLayerData(const char *layer_name);
private:
BoundingBox BinaryToBBox(const uint8_t *binary, uint length);
PGconn *conn;
};
#endif /* __DBCONN_H_ */
--- NEW FILE: Makefile.am ---
noinst_LTLIBRARIES =
if INCLUDE_POSTGIS
noinst_LTLIBRARIES += libpostgis.la
endif
AM_CPPFLAGS = -Wall -I$(top_srcdir) $(LIBPQXX_CFLAGS)
libpostgis_la_SOURCES = postgis.cc dbconn.cc dbconn.h
libpostgis_la_LIBADD = @GEOS_LIBS@
--- NEW FILE: postgis.cc ---
/*
* Player - One Hell of a Robot Server
* Copyright (C) 2004 Brian Gerkey [EMAIL PROTECTED]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* $Id: postgis.cc,v 1.1 2007/08/20 19:42:48 thjc Exp $
*
* A driver to use a vector map with a PostGIS backend.
*/
/** @ingroup drivers */
/** @{ */
/** @defgroup driver_PostGIS PostGIS
* @brief Vectormap driver based on a Postgresql database with the PostGIS
plugin.
@par Provides
- @ref interface_vectormap
@par Requires
- None
@par Configuration requests
- None
@par Configuration file options
- dbname (string)
- Default: template1
- The name of the Postgresql database to connect to.
- host (string)
- Default: localhost
- The name of the database host.
- user (string)
- Default: postgres
- The name of the database user.
- port (string)
- Default: 5432
- The port of the database.
- password (string)
- Default: empty string
- The password for the database user
- layers (string tuple)
- Default: Field required
- Names of the layers. The layers are named after the corresponding tables in
the database.
@par Example
@verbatim
driver
(
dbname "gis"
host "192.168.0.2"
port "5433"
user "postgres"
password "secret"
layers ["obstacles_geom" "markers_geom"]
)
@endverbatim
@par Creating a PostGIS Database
///TODO: Add documentation
For more information see http://postgis.refractions.net/
@par Database schema
///TODO: Add documentation
@author Ben Morelli
*/
/** @} */
#include <sys/types.h> // required by Darwin
#include <stdlib.h>
#include <libplayercore/playercore.h>
#include <libplayercore/error.h>
#include <playererror.h>
#include "dbconn.h"
#ifdef HAVE_GEOS
#include <geos_c.h>
#endif
/** Dummy function passed as a function pointer GEOS when it is initialised.
GEOS uses this for logging. */
void geosprint(const char *text, ...)
{
return;
}
////////////////////////////////////////////////////////////////////////////////
class PostGIS : public Driver
{
public:
PostGIS(ConfigFile* cf, int section,
const char* dbname,
const char* host,
const char* user,
const char* password,
const char* port,
vector<string> layerNames);
~PostGIS();
int Setup();
int Shutdown();
// MessageHandler
int ProcessMessage(MessageQueue * resp_queue,
player_msghdr * hdr,
void * data);
private:
void RequestLayerWrite(player_vectormap_layer_data_t* data);
VectorMapInfoHolder RequestVectorMapInfo();
LayerInfoHolder RequestLayerInfo(const char* layer_name);
LayerDataHolder RequestLayerData(const char* layer_name);
const char* dbname;
const char* host;
const char* user;
const char* password;
const char* port;
vector<string> layerNames;
PostgresConn *conn;
};
////////////////////////////////////////////////////////////////////////////////
Driver* PostGIS_Init(ConfigFile* cf, int section)
{
const char* dbname = cf->ReadString(section,"dbname", "template1");
const char* host = cf->ReadString(section,"host", "localhost");
const char* user = cf->ReadString(section,"user", "postgres");
const char* password = cf->ReadString(section,"password", "");
const char* port = cf->ReadString(section,"port", "5432");
vector<string> layerNames;
int layers_count = cf->GetTupleCount(section, "layers");
if (layers_count < 1)
{
PLAYER_ERROR("There must be at least one layer defined in the 'layers'
configuration field.");
return NULL;
}
for (int i=0; i<layers_count; ++i)
{
const char* layer_name = cf->ReadTupleString(section, "layers", i, "");
layerNames.push_back(string(layer_name));
}
return((Driver*)(new PostGIS(cf, section, dbname, host, user, password, port,
layerNames)));
}
////////////////////////////////////////////////////////////////////////////////
// a driver registration function
void PostGIS_Register(DriverTable* table)
{
table->AddDriver("postgis", PostGIS_Init);
}
////////////////////////////////////////////////////////////////////////////////
PostGIS::PostGIS(ConfigFile* cf, int section,
const char* dbname,
const char* host,
const char* user,
const char* password,
const char* port,
vector<string> layerNames)
: Driver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN,
PLAYER_VECTORMAP_CODE)
{
this->dbname = dbname;
this->host = host;
this->user = user;
this->password = password;
this->port = port;
this->layerNames = layerNames;
this->conn = NULL;
}
////////////////////////////////////////////////////////////////////////////////
PostGIS::~PostGIS()
{
/*if (conn != NULL && conn->Connected())
{
conn->Disconnect();
}
if (conn != NULL)
{
printf("DELETING CONNECTION\n");
delete conn;
conn = NULL;
}*/
}
////////////////////////////////////////////////////////////////////////////////
// Load resources
int PostGIS::Setup()
{
PLAYER_MSG0(2, "PostGIS vectormap initialising");
#ifdef HAVE_GEOS
PLAYER_MSG0(2, "Initialising GEOS");
initGEOS(geosprint, geosprint);
PLAYER_MSG0(2, "GEOS Initialised");
#endif
conn = new PostgresConn();
conn->Connect(dbname, host, user, password, port);
if (!conn->Connected())
{
PLAYER_ERROR("Could not connect to Postgres database!");
PLAYER_ERROR1("%s",conn->ErrorMessage());
return(1);
}
PLAYER_MSG0(2, "PostGIS vectormap ready");
return(0);
}
////////////////////////////////////////////////////////////////////////////////
// Clean up resources
int PostGIS::Shutdown()
{
PLAYER_MSG0(2, "PostGIS vectormap shutting down");
if (conn != NULL && conn->Connected())
{
PLAYER_MSG0(2, "Disconnecting database");
conn->Disconnect();
}
if (conn != NULL)
{
delete conn;
//conn == NULL;
}
#ifdef HAVE_GEOS
PLAYER_MSG0(2, "Shutting down GEOS");
finishGEOS();
#endif
PLAYER_MSG0(2, "PostGIS vectormap stopped");
return(0);
}
////////////////////////////////////////////////////////////////////////////////
// Process an incoming message
int PostGIS::ProcessMessage(MessageQueue * resp_queue,
player_msghdr * hdr,
void * data)
{
// Request for map info
///////////////////////////////////////////////////////////
if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_VECTORMAP_REQ_GET_MAP_INFO,
this->device_addr))
{
if (hdr->size != 0)
{
PLAYER_ERROR2("request is wrong length (%d != %d); ignoring",
hdr->size, 0);
return -1;
}
VectorMapInfoHolder info = RequestVectorMapInfo();
const player_vectormap_info_t* response = info.Convert();
this->Publish(this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_VECTORMAP_REQ_GET_MAP_INFO,
(void*)response,
sizeof(player_vectormap_info_t),
NULL);
return(0);
}
// Request for layer info
/////////////////////////////////////////////////////////
else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_VECTORMAP_REQ_GET_LAYER_INFO,
this->device_addr))
{
if (hdr->size != sizeof(player_vectormap_layer_info_t))
{
PLAYER_ERROR2("request is wrong length (%d != %d); ignoring",
hdr->size, 0);
return -1;
}
const player_vectormap_layer_info_t* request =
reinterpret_cast<player_vectormap_layer_info_t*>(data);
LayerInfoHolder info = RequestLayerInfo(request->name);
const player_vectormap_layer_info_t* response = info.Convert();
this->Publish(this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_VECTORMAP_REQ_GET_LAYER_INFO,
(void*)response,
sizeof(player_vectormap_layer_info_t),
NULL);
return(0);
}
// Request for layer data
/////////////////////////////////////////////////////////
else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_VECTORMAP_REQ_GET_LAYER_DATA,
this->device_addr))
{
if (hdr->size != sizeof(player_vectormap_layer_data_t))
{
PLAYER_ERROR2("request is wrong length (%d != %d); ignoring",
hdr->size, 0);
return -1;
}
player_vectormap_layer_data_t* request =
reinterpret_cast<player_vectormap_layer_data_t*>(data);
LayerDataHolder ldata = RequestLayerData(request->info.name);
const player_vectormap_layer_data_t* response = ldata.Convert();
this->Publish(this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_VECTORMAP_REQ_GET_LAYER_DATA,
(void*)response,
sizeof(player_vectormap_layer_data_t),
NULL);
return(0);
}
// Request to write layer data
///////////////////////////////////////////////////
else if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ,
PLAYER_VECTORMAP_REQ_WRITE_LAYER,
this->device_addr))
{
if (hdr->size != 0)
{
PLAYER_ERROR2("request is wrong length (%d != %d); ignoring",
hdr->size, 0);
return -1;
}
player_vectormap_layer_data_t* request =
reinterpret_cast<player_vectormap_layer_data_t*>(data);
RequestLayerWrite(request);
this->Publish(this->device_addr,
resp_queue,
PLAYER_MSGTYPE_RESP_ACK,
PLAYER_VECTORMAP_REQ_WRITE_LAYER,
(void*)request,
sizeof(player_vectormap_layer_data_t),
NULL);
return(0);
}
// Don't know how to handle this message
/////////////////////////////////////////
return(-1);
}
VectorMapInfoHolder PostGIS::RequestVectorMapInfo()
{
if (conn == NULL || conn->Connected() == false)
{
PLAYER_ERROR("PostGis::RequestVectorMapInfo() failed! No db connection.");
}
VectorMapInfoHolder info = conn->GetVectorMapInfo(layerNames);
return info;
}
LayerInfoHolder PostGIS::RequestLayerInfo(const char* layer_name)
{
if (conn == NULL || conn->Connected() == false)
{
PLAYER_ERROR("PostGis::RequestLayerInfo() failed! No db connection.");
}
LayerInfoHolder info = conn->GetLayerInfo(layer_name);
return info;
}
LayerDataHolder PostGIS::RequestLayerData(const char* layer_name)
{
if (conn == NULL || conn->Connected() == false)
{
PLAYER_ERROR("PostGis::RequestLayerData() failed! No db connection.");
}
LayerDataHolder data = conn->GetLayerData(layer_name);
return data;
}
void PostGIS::RequestLayerWrite(player_vectormap_layer_data_t* data)
{
return;
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit