382 lines
10 KiB
C
382 lines
10 KiB
C
/*------------------------------------------------------------------------------
|
|
* gis.c: GIS data functions
|
|
*
|
|
* Copyright (C) 2016 by T.TAKASU, All rights reserved.
|
|
*
|
|
* references:
|
|
* [1] ESRI Shapefile Technical Description, An ESRI White Paper, July, 1998
|
|
*
|
|
* version : $Revision:$ $Date:$
|
|
* history : 2016/06/10 1.0 new
|
|
* 2016/07/31 1.1 add boundary of polyline and polygon
|
|
*-----------------------------------------------------------------------------*/
|
|
#include "rtklib.h"
|
|
|
|
#define SHAPE_CODE 9994 /* shapefile code */
|
|
|
|
/* get integer big-endian ----------------------------------------------------*/
|
|
static int I4_B(uint8_t *buff)
|
|
{
|
|
int i,val=0;
|
|
uint8_t *p=buff,*q=(uint8_t *)&val+3;
|
|
|
|
for (i=0;i<4;i++) {
|
|
*q--=*p++;
|
|
}
|
|
return val;
|
|
}
|
|
/* get integer little-endian -------------------------------------------------*/
|
|
static int I4_L(uint8_t *buff)
|
|
{
|
|
int val;
|
|
|
|
memcpy(&val,buff,4);
|
|
return val;
|
|
}
|
|
/* get double little-endian --------------------------------------------------*/
|
|
static double D8_L(uint8_t *buff)
|
|
{
|
|
double val;
|
|
|
|
memcpy(&val,buff,8);
|
|
return val;
|
|
}
|
|
/* read shapefile header -----------------------------------------------------*/
|
|
static int read_shape_head(FILE *fp)
|
|
{
|
|
uint8_t buff[128];
|
|
|
|
if (fread(buff,100,1,fp)!=1) {
|
|
return -1;
|
|
}
|
|
if (I4_B(buff)!=SHAPE_CODE) {
|
|
return -1;
|
|
}
|
|
return I4_L(buff+32);
|
|
}
|
|
/* initialize boundary -------------------------------------------------------*/
|
|
static void init_bound(double *bound)
|
|
{
|
|
bound[0]= PI/2.0;
|
|
bound[1]=-PI/2.0;
|
|
bound[2]= PI;
|
|
bound[3]=-PI;
|
|
}
|
|
/* update boundary -----------------------------------------------------------*/
|
|
static void update_bound(const double *pos, double *bound)
|
|
{
|
|
if (pos[0]<bound[0]) bound[0]=pos[0];
|
|
if (pos[0]>bound[1]) bound[1]=pos[0];
|
|
if (pos[1]<bound[2]) bound[2]=pos[1];
|
|
if (pos[1]>bound[3]) bound[3]=pos[1];
|
|
}
|
|
/* add gis data --------------------------------------------------------------*/
|
|
static int gis_add(gisd_t **p, int type, void *data)
|
|
{
|
|
gisd_t *new_data;
|
|
|
|
if (!(new_data=(gisd_t *)malloc(sizeof(gisd_t)))) {
|
|
return 0;
|
|
}
|
|
new_data->next=*p;
|
|
new_data->type=type;
|
|
new_data->data=data;
|
|
*p=new_data;
|
|
return 1;
|
|
}
|
|
/* read point data -----------------------------------------------------------*/
|
|
static int read_pnt(FILE *fp, double *bound, gisd_t **p)
|
|
{
|
|
gis_pnt_t *pnt;
|
|
double pos[3]={0};
|
|
uint8_t buff[16];
|
|
|
|
if (fread(buff,16,1,fp)!=1) {
|
|
return 0;
|
|
}
|
|
if (!(pnt=(gis_pnt_t *)malloc(sizeof(gis_pnt_t)))) {
|
|
return 0;
|
|
}
|
|
pos[0]=D8_L(buff+8)*D2R;
|
|
pos[1]=D8_L(buff )*D2R;
|
|
update_bound(pos,bound);
|
|
pos2ecef(pos,pnt->pos);
|
|
|
|
return gis_add(p,1,pnt);
|
|
}
|
|
/* read multi-point data ------------------------------------------------------*/
|
|
static int read_mpnt(FILE *fp, double *bound, gisd_t **p)
|
|
{
|
|
uint8_t buff[36];
|
|
int i,np;
|
|
|
|
if (fread(buff,36,1,fp)!=1) {
|
|
return 0;
|
|
}
|
|
np=I4_L(buff+32);
|
|
|
|
for (i=0;i<np;i++) {
|
|
if (!read_pnt(fp,bound,p)) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/* read polyline data ---------------------------------------------------------*/
|
|
static int read_poly(FILE *fp, double *bound, gisd_t **p)
|
|
{
|
|
gis_poly_t *poly;
|
|
double pos[3]={0};
|
|
uint8_t buff[40];
|
|
int i,j,nt,np,nr,n,*part;
|
|
|
|
if (fread(buff,40,1,fp)!=1) {
|
|
return 0;
|
|
}
|
|
nt=I4_L(buff+32);
|
|
np=I4_L(buff+36);
|
|
|
|
if (!(part=(int *)malloc(sizeof(int)*nt))) {
|
|
return 0;
|
|
}
|
|
for (i=0;i<nt;i++) {
|
|
fread(buff,4,1,fp);
|
|
part[i]=I4_L(buff);
|
|
}
|
|
for (i=0;i<nt;i++) {
|
|
nr=(i<nt-1?part[i+1]:np)-part[i];
|
|
|
|
if (!(poly=(gis_poly_t *)malloc(sizeof(gis_poly_t)))) {
|
|
free(part);
|
|
return 0;
|
|
}
|
|
if (!(poly->pos=(double *)malloc(sizeof(double)*nr*3))) {
|
|
free(poly);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
init_bound(poly->bound);
|
|
|
|
for (j=n=0;j<nr;j++) {
|
|
if (fread(buff,16,1,fp)!=1) {
|
|
free(poly->pos);
|
|
free(poly);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
pos[0]=D8_L(buff+8)*D2R;
|
|
pos[1]=D8_L(buff )*D2R;
|
|
if (pos[0]<-1E16||pos[1]<-1E16) {
|
|
continue;
|
|
}
|
|
update_bound(pos,poly->bound);
|
|
update_bound(pos,bound);
|
|
pos2ecef(pos,poly->pos+n*3);
|
|
n++;
|
|
}
|
|
poly->npnt=n;
|
|
if (!gis_add(p,2,(void *)poly)) {
|
|
free(poly->pos);
|
|
free(poly);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
}
|
|
free(part);
|
|
return 1;
|
|
}
|
|
/* read polygon data ---------------------------------------------------------*/
|
|
static int read_polygon(FILE *fp, double *bound, gisd_t **p)
|
|
{
|
|
gis_polygon_t *polygon;
|
|
double pos[3]={0};
|
|
uint8_t buff[40];
|
|
int i,j,nt,np,nr,n,*part;
|
|
|
|
if (fread(buff,40,1,fp)!=1) {
|
|
return 0;
|
|
}
|
|
nt=I4_L(buff+32);
|
|
np=I4_L(buff+36);
|
|
|
|
if (!(part=(int *)malloc(sizeof(int)*nt))) {
|
|
return 0;
|
|
}
|
|
for (i=0;i<nt;i++) {
|
|
fread(buff,4,1,fp);
|
|
part[i]=I4_L(buff);
|
|
}
|
|
for (i=0;i<nt;i++) {
|
|
nr=(i<nt-1?part[i+1]:np)-part[i];
|
|
|
|
if (!(polygon=(gis_polygon_t *)malloc(sizeof(gis_poly_t)))) {
|
|
free(part);
|
|
return 0;
|
|
}
|
|
if (!(polygon->pos=(double *)malloc(sizeof(double)*nr*3))) {
|
|
free(polygon);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
init_bound(polygon->bound);
|
|
|
|
for (j=n=0;j<nr;j++) {
|
|
if (fread(buff,16,1,fp)!=1) {
|
|
free(polygon->pos);
|
|
free(polygon);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
pos[0]=D8_L(buff+8)*D2R;
|
|
pos[1]=D8_L(buff )*D2R;
|
|
if (pos[0]<-1E16||pos[1]<-1E16) {
|
|
continue;
|
|
}
|
|
update_bound(pos,polygon->bound);
|
|
update_bound(pos,bound);
|
|
pos2ecef(pos,polygon->pos+n*3);
|
|
n++;
|
|
}
|
|
polygon->npnt=n;
|
|
if (!gis_add(p,3,(void *)polygon)) {
|
|
free(polygon->pos);
|
|
free(polygon);
|
|
free(part);
|
|
return 0;
|
|
}
|
|
}
|
|
free(part);
|
|
return 1;
|
|
}
|
|
/* read shapefile records ----------------------------------------------------*/
|
|
static int gis_read_record(FILE *fp, FILE *fp_idx, int type, double *bound,
|
|
gisd_t **data)
|
|
{
|
|
gisd_t *p,*next;
|
|
uint8_t buff[16];
|
|
int i,off,num,len1,len2,typ2;
|
|
|
|
for (i=0;fread(buff,1,8,fp_idx)==8;i++) {
|
|
off =I4_B(buff )*2;
|
|
len1=I4_B(buff+4)*2;
|
|
|
|
if (fseek(fp,(long)off,SEEK_SET)<0||fread(buff,12,1,fp)!=1) {
|
|
return 0;
|
|
}
|
|
num =I4_B(buff );
|
|
len2=I4_B(buff+4)*2;
|
|
typ2=I4_L(buff+8);
|
|
|
|
if (num!=i+1||len1!=len2||type!=typ2) {
|
|
trace(2,"shapefile record error n=%d %d len=%d %d type=%d %d\n",
|
|
i+1,num,len1,len2,type,typ2);
|
|
continue;
|
|
}
|
|
if (type==1) { /* point */
|
|
read_pnt(fp,bound,data);
|
|
}
|
|
else if (type==8) { /* multi-point */
|
|
read_mpnt(fp,bound,data);
|
|
}
|
|
else if (type==3) { /* polyline */
|
|
read_poly(fp,bound,data);
|
|
}
|
|
else if (type==5) { /* polygon */
|
|
read_polygon(fp,bound,data);
|
|
}
|
|
else { /* skip record */
|
|
for (i=0;i<len1-4;i++) {
|
|
fread(buff,1,1,fp);
|
|
}
|
|
}
|
|
}
|
|
/* reverse list order */
|
|
for (p=*data,*data=NULL;p;p=next) {
|
|
next=p->next;
|
|
p->next=*data;
|
|
*data=p;
|
|
}
|
|
return 1;
|
|
}
|
|
/* read gis data from shapefile ------------------------------------------------
|
|
* read gis data from shapefile (ref [1])
|
|
* args : char *file I shapefile
|
|
* gis_t *gis IO GIS data
|
|
* return : status (0:error)
|
|
* notes : only support point, multipoint, polyline and polygon.
|
|
* only support lat-lon for map projection.
|
|
*-----------------------------------------------------------------------------*/
|
|
extern int gis_read(const char *file, gis_t *gis, int layer)
|
|
{
|
|
FILE *fp,*fp_idx;
|
|
char path[1024],*p,*q;
|
|
int type1=0,type2=0;
|
|
|
|
trace(3,"gis_read file=%s layer=%d\n",file,layer);
|
|
|
|
strcpy(path,file);
|
|
|
|
if ((p=strrchr(path,'.'))) {
|
|
sprintf(p,".shx");
|
|
}
|
|
else {
|
|
sprintf(path+strlen(path),".shx");
|
|
}
|
|
if (!(fp=fopen(file,"rb"))) { /* shapefile */
|
|
trace(2,"shapefile open error: %s\n",file);
|
|
return 0;
|
|
}
|
|
if (!(fp_idx=fopen(path,"rb"))) { /* index file */
|
|
fclose(fp);
|
|
trace(2,"shapefile index open error: %s\n",path);
|
|
return 0;
|
|
}
|
|
/* read header */
|
|
if ((type1=read_shape_head(fp))<0||(type2=read_shape_head(fp_idx))<0||
|
|
type1!=type2) {
|
|
trace(2,"shapefile header error: %s type=%d %d\n",file,type1,type2);
|
|
fclose(fp);
|
|
fclose(fp_idx);
|
|
return 0;
|
|
}
|
|
init_bound(gis->bound);
|
|
|
|
/* read records */
|
|
if (!gis_read_record(fp,fp_idx,type1,gis->bound,gis->data+layer)) {
|
|
fclose(fp);
|
|
fclose(fp_idx);
|
|
return 0;
|
|
}
|
|
fclose(fp);
|
|
fclose(fp_idx);
|
|
gis->name[layer][0]='\0';
|
|
gis->flag[layer]=1;
|
|
return 1;
|
|
}
|
|
/* free gis-data ---------------------------------------------------------------
|
|
* free and initialize gis data
|
|
* args : gis_t *gis IO gis data
|
|
* return : none
|
|
*-----------------------------------------------------------------------------*/
|
|
extern void gis_free(gis_t *gis)
|
|
{
|
|
gisd_t *data,*next;
|
|
int i;
|
|
|
|
for (i=0;i<MAXGISLAYER;i++) {
|
|
for (data=gis->data[i];data;data=next) {
|
|
next=data->next;
|
|
if (data->type==2) {
|
|
free(((gis_poly_t *)data->data)->pos);
|
|
}
|
|
else if (data->type==3) {
|
|
free(((gis_polygon_t *)data->data)->pos);
|
|
}
|
|
free(data);
|
|
}
|
|
gis->data[i]=NULL;
|
|
gis->name[i][0]='\0';
|
|
gis->flag[i]=0;
|
|
}
|
|
}
|