that's my first version of a .shp file - lines/polygons reader
usage:
Code: Select all
//Rios
moRivers->clear();
ShapeFile* sfRivers = new ShapeFile();
sfRivers->load("data/rivers/all.shp");
sfRivers->setCanvas(*moRivers,*mTerrainGroup,"matRivers");
sfRivers->setCoords(newSide*pixelSize,newSide*pixelSize,LONGMIN,LONGMAX,LATMIN,LATMAX);
sfRivers->draw();
delete sfRivers;
Code: Select all
#include <Ogre.h>
#include <Terrain/OgreTerrain.h>
#include <Terrain/OgreTerrainGroup.h>
typedef std::deque <std::string> record_t;
typedef std::deque <record_t> table_t;
//-------------------------------------------------------------------------------------
bool fileExists(std::string strFilename)
{
struct stat stFileInfo;
return (stat(strFilename.c_str(),&stFileInfo) == 0);
}
//-------------------------------------------------------------------------------------
std::string lowerCase(std::string s)
{
for (unsigned int i=0; i<s.length(); i++)
s[i] = tolower(s[i]);
return s;
}
//-------------------------------------------------------------------------------------
std::string upperCase(std::string s)
{
for (unsigned int i=0; i<s.length(); i++)
s[i] = toupper(s[i]);
return s;
}
//-------------------------------------------------------------------------------------
double readDouble(std::ifstream& f)
{
double X;
f.read(reinterpret_cast<char*>(&X),8);
return X;
}
//-------------------------------------------------------------------------------------
Ogre::String strAsBin(char* str, int count)
{
int i=0;
char bch;
uint8_t b, c, ind;
Ogre::String byte;
Ogre::String resposta = "";
do {
byte = "00000000";
if (str[i] != 0) {
bch = str[i];
b = bch;
ind = 7;
while (b > 1) {
c = b%2;
if (c == 1)
byte[ind] = '1';
b = b/2;
ind--;
}
byte[ind] = '1';
}
i++;
resposta = resposta + '|' + byte;
} while (i < count);
return resposta;
}
//-------------------------------------------------------------------------------------
uint leBig(std::ifstream& f)
{
char *buf;
Ogre::uint32 num;
Ogre::uint8 num1, num2, num3, num4;
buf = new char[4];
f.read(buf,4);
num1 = buf[0];
num2 = buf[1];
num3 = buf[2];
num4 = buf[3];
num = num1*0x1000000 +
num2*0x10000 +
num3*0x100 +
num4;
delete[] buf;
return num;
}
//-------------------------------------------------------------------------------------
uint leLittle(std::ifstream& f)
{
char *buf;
Ogre::uint32 num;
Ogre::uint8 num1, num2, num3, num4;
buf = new char[4];
f.read(buf,4);
num1 = buf[0];
num2 = buf[1];
num3 = buf[2];
num4 = buf[3];
num = num4*0x1000000 +
num3*0x10000 +
num2*0x100 +
num1;
delete[] buf;
return num;
}
//-------------------------------------------------------------------------------------
bool compareCaseless(std::string s1, std::string s2)
{
return (upperCase(s1) == upperCase(s2));
}
//-------------------------------------------------------------------------------------
void csv2table(std::istream& ins, table_t& table, char sep)
{
std::string s;
table.clear();
while (std::getline( ins, s ))
{
std::istringstream ss( s );
record_t record;
std::string field;
bool final = true;
while (std::getline( ss, field, sep ))
{
record.push_back( field );
final = ss.eof();
}
if (!final)
record.push_back( std::string() );
table.push_back( record );
}
}
//-------------------------------------------------------------------------------------
std::string formatFloat(float number,int decPlaces,char thSep)
{
int sinal = 1;
if (number < 0) {
number = -number;
sinal = -1;
}
float numberOrig = number;
int pos, count = 0;
std::string resp = "";
char respost[2];
do {
pos = int(floor(number)) % 10;
sprintf(respost,"%d",pos); // converts to decimal base (which is faster? sprintf or Ogre::StringConverter::toString?
resp = respost + resp;
if ((count%3 == 2) && (number >= 10) && (thSep != ' '))
resp = thSep + resp;
number /= 10;
count++;
} while (number > 1);
if (decPlaces > 0) { // decimal places
number=numberOrig - abs(numberOrig); // fractional part
count = 0;
if (thSep == '.')
resp = resp + ',';
else
resp = resp + '.';
do {
number *= 10;
pos = floor(number);
number -= pos;
resp = resp + char(48+pos);//Ogre::StringConverter::toString(pos);
count++;
} while (count < decPlaces);
}
if (sinal < 0)
resp = "-" + resp;
return resp;
}
//-------------------------------------------------------------------------------------
//determines if a point is inside a polygon
//from http://www.visibone.com/inpoly/
int /* 1=inside, 0=outside */
inpoly( /* is target point inside a 2D polygon? */
unsigned int poly[][2], /* polygon points, [0]=x, [1]=y */
int npoints, /* number of points in polygon */
unsigned int xt, /* x (horizontal) of target point */
unsigned int yt) /* y (vertical) of target point */
{
unsigned int xnew,ynew;
unsigned int xold,yold;
unsigned int x1,y1;
unsigned int x2,y2;
int i;
int inside=0;
if (npoints < 3) {
return(0);
}
xold=poly[npoints-1][0];
yold=poly[npoints-1][1];
for (i=0 ; i < npoints ; i++) {
xnew=poly[i][0];
ynew=poly[i][1];
if (xnew > xold) {
x1=xold;
x2=xnew;
y1=yold;
y2=ynew;
}
else {
x1=xnew;
x2=xold;
y1=ynew;
y2=yold;
}
if ((xnew < xt) == (xt <= xold) /* edge "open" at one end */
&& ((long)yt-(long)y1)*(long)(x2-x1)
< ((long)y2-(long)y1)*(long)(xt-x1)) {
inside=!inside;
}
xold=xnew;
yold=ynew;
}
return(inside);
}
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
// ShapeFile object
//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
using namespace std;
struct point2d
{
float lat, lon;
};
typedef std::vector<point2d> segment;
typedef std::vector<segment> polygon;
//-------------------------------------------------------------------------------------
class ShapeFile {
private:
polygon Poly;
//segment Segm;
size_t nPoints; //nParts, nPoints, actualPart;
ifstream fShp;
Ogre::ManualObject* mo;
Ogre::TerrainGroup* tg;
string matName;
Ogre::Rectangle BBox;
int W,H;
public:
ShapeFile(void);
~ShapeFile(void);
int load(std::string fName);
void readRec(void);
void linhaTerreno(double x,double z);
int setCanvas(Ogre::ManualObject &l,Ogre::TerrainGroup &t,string mn);
int setCoords(int w,int h,float left,float right,float bottom,float top);
//int setCoords(int w,int h,Ogre::Rectangle bbox);
int draw(void);
};
//-------------------------------------------------------------------------------------
ShapeFile::ShapeFile(void) :
//nParts(0),
nPoints(0),
mo(0),
tg(0),
matName(""),
W(0),
H(0)
//actualPart(0)
{
}
//-------------------------------------------------------------------------------------
ShapeFile::~ShapeFile(void)
{
if (Poly.size() > 0)
Poly.clear();
}
//-------------------------------------------------------------------------------------
int ShapeFile::load(std::string fName)
{
//cout << "shapeFile:" << fName << '\n';
Ogre::String fName2 = lowerCase(fName);
if (fileExists(fName) || fileExists(fName2)) {
if (fileExists(fName))
fShp.open(fName.c_str(),std::ios::binary); // with uppercase
else
fShp.open(fName2.c_str(),std::ios::binary); // all lowercase
if (fShp.is_open()) {
char* offsetHeader = new char[72];
fShp.read(offsetHeader,24); // reads the begin of the file's header
uint fSize = leBig(fShp)*2;
fShp.read(offsetHeader,72); // reads the remaining of the file's header...
delete[] offsetHeader; // ... and throws it away
while (fShp.tellg() < fSize) {
//linha->begin("matLevel4",Ogre::RenderOperation::OT_LINE_STRIP);
readRec(); // read and draw the roads
}
fShp.close();
} else return 1; // file couldn't be opened
} else return 2; // file couldn't be found
return 0; // all right
}
//-------------------------------------------------------------------------------------
// File format explained in "ESRI Shapefile Technical Description" (shapefile.pdf) - http://www.esri.com
void ShapeFile::readRec(void)
{
uint nparts, npoints, i, part;
point2d point;
segment segm;
size_t j;
std::vector<uint> parts;
fShp.ignore(8);
uint tipo = leLittle(fShp);
if (tipo == 3 || tipo == 5) { // PolyLine or Polygon
fShp.ignore(32);
// reads number of parts and points of this record/polygon
nparts = leLittle(fShp);
//nparts += nparts;
npoints = leLittle(fShp);
nPoints += npoints;
// read all the parts at once and put their positions (relative to this record) in parts' vector
// first part always begins at 0
for (i=0; i<nparts; i++) {
part = leLittle(fShp);
parts.push_back(part);
}
if (nparts > 1)
part = parts[1]; // where the first part will end (the beginning of the 2nd part [1])
else
part = 0;
j = 1; // reading first part
for (i=0; i<npoints; i++) {
point.lon = readDouble(fShp); // longitude
point.lat = readDouble(fShp); // latitude
if (i == part) // end of the current part (j) or first time of 1 part's record
{
if (i > 0) { // won't do if record has only 1 part (and i=part=0)
Poly.push_back(segm);
//actualPart++;
segm.clear();
//segm = new segment; // dettach??????????????????????????????????????????????????
/*
linha->end(); // jump to another polygon
linha->begin("matLevel4",Ogre::RenderOperation::OT_LINE_STRIP);
*/
}
segm.push_back(point);
//linhaTerreno(linha,X,Y); // add point to current polygon
if (j < parts.size()) { // adjust limit (end point) of next part
j++;
if (j < parts.size())
part = parts[j];
else
part = -1; // will end the loop by i=nPoints (since its the last part)
}
}
else // i != part, all points inside any part
{
segm.push_back(point);
//linhaTerreno(linha,X,Y);
}
} // for i
// draw remaining points
Poly.push_back(segm);
//linha->end();
} // if (tipo==3 || tipo==5)
}
//-------------------------------------------------------------------------------------
void ShapeFile::linhaTerreno(double x,double z)
{
mo->position(x,tg->getHeightAtWorldPosition(x,0,z),z);
}
//-------------------------------------------------------------------------------------
int ShapeFile::setCanvas(Ogre::ManualObject &l,Ogre::TerrainGroup &t,string mn)
{
//cout << "MATERIAL:" << mn << '\n';
mo = &l;
tg = &t;
matName = mn;
return 0;
}
//-------------------------------------------------------------------------------------
int ShapeFile::setCoords(int w,int h,float left,float right,float bottom,float top)
{
W = w;
H = h;
BBox.left = left;
BBox.right = right;
BBox.bottom = bottom;
BBox.top = top;
return 0;
}
//-------------------------------------------------------------------------------------
int ShapeFile::draw(void)
{
if ((W == 0) || (H == 0))
return 1; // image null
//cout << "*************************" << Poly.size() << '\n';
for (size_t p=0; p<Poly.size(); p++) {
segment segm = Poly[p];
mo->begin(matName,Ogre::RenderOperation::OT_LINE_STRIP);
for (size_t s=0; s<segm.size(); s++) {
double X = W*(segm[s].lon-BBox.left)/(BBox.right-BBox.left) - W/2; // map X
double Y = H*(BBox.top-segm[s].lat)/(BBox.top-BBox.bottom) - H/2; // map Y
linhaTerreno(X,Y);
//mo->position(x,tg->getHeightAtWorldPosition(x,0,z),z);
}
mo->end();
}
return 0;
}
//-------------------------------------------------------------------------------------
RLD