Files
vroni/io_misc.cc
T
SaraP 739088af9f Vroni 7.8 :
- aggiornamento versione.
2025-01-29 16:24:30 +01:00

823 lines
24 KiB
C++

/*****************************************************************************/
/* */
/* Copyright (C) 2002-2025 M. Held */
/* */
/* This code is not in the public domain. All rights reserved! Please make */
/* sure to read the full copyright statement contained in "README.pdf" or in */
/* the "main" file of this code, such as "main.cc". */
/* */
/*****************************************************************************/
/* */
/* Written by: Martin Held */
/* */
/* E-Mail: held@cs.sbg.ac.at */
/* Fax Mail: (+43 662) 8044-172 */
/* Voice Mail: (+43 662) 8044-6304 */
/* Snail Mail: Martin Held */
/* FB Informatik */
/* Universitaet Salzburg */
/* A-5020 Salzburg, Austria */
/* */
/* Acknowledgment: XML input coded by Christian Spielberger. */
/* */
/* */
/*****************************************************************************/
/* */
/* provide support for .e00 and other miscellaneous input formats. */
/* */
/*****************************************************************************/
/* */
/* get standard libraries */
/* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
/* */
/* get my header files */
/* */
#include "fpkernel.h"
#include "vronivector.h"
#include "vroni_object.h"
#include "defs.h"
/* */
/* move file pointer to next line */
/* */
#define F_NEW_LINE \
{while (((c=fgetc(input)) != '\n') && ( c != EOF)) {}}
/* */
/* This function multiplies a point (x, y) with a homogeneous transformation */
/* matrix. Thus, */
/* */
/* x_new = a11 * x_old + a12 * y_old + vx, */
/* y_new = a21 * x_old + a22 * y_old + vy. */
/* */
void Transform(double *x, double *y, double_arg a11, double_arg a21, double_arg a12,
double_arg a22, double_arg vx, double_arg vy)
{
double x0, y0;
x0 = *x;
y0 = *y;
*x = a11 * x0 + a12 * y0 + vx;
*y = a21 * x0 + a22 * y0 + vy;
return;
}
/* */
/* this function reads data in USGS format. every polygonal chain is */
/* specified as a sequence of (x,y)-pairs. note that all coordinates are */
/* positive; a negative coordinate serves as a delimiter between chains. */
/* also, we do not take care of isolated points! */
/* */
void vroniObject::ReadUSGS(char input_file[], vr_bool *new_input)
{
double xc1, yc1;
int i1, number = 0;
FILE *input;
input = OpenFileVD(input_file, "r");
*new_input = false;
isolated_pnts = false;
while (EOF != FP_fscanf(input, "%lf", &xc1)) {
if (xc1 < 0.0) {
/* */
/* end of the last polygonal chain */
/* */
if (number > 0) {
if (number == 1)
isolated_pnts = true;
*new_input = true;
}
number = 0;
}
else {
if (EOF == FP_fscanf(input, "%lf", &yc1))
throw std::runtime_error("VRONI error: ReadUSGS() - premature end of file!");
#ifdef EXT_APPL_PNTS
if (number == 0)
i1 = HandlePnt(xc1, yc1, eap_NIL);
#else
if (number == 0)
i1 = HandlePnt(xc1, yc1);
#endif
#ifdef EXT_APPL_SITES
else
AddSeg(&i1, xc1, yc1, eas_NIL);
#else
else
AddSeg(&i1, xc1, yc1);
#endif
++number;
}
}
fclose(input);
return;
}
void vroniObject::SkipText(FILE *in_file, char ch)
{
char dummy;
do {
if (fscanf(in_file, "%c", &dummy) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
}
while (dummy != ch);
return;
}
char vroniObject::ParseText(FILE *in_file, char ch1, char ch2)
{
char dummy;
if (fscanf(in_file, "%c", &dummy) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
if ((dummy == ch1) || (dummy == ch2))
return dummy;
if (fscanf(in_file, "%c", &dummy) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
if ((dummy == ch1) || (dummy == ch2))
return dummy;
if (fscanf(in_file, "%c", &dummy) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
return dummy;
}
vr_bool vroniObject::FindText(FILE *in_file, char ch)
{
char dummy;
do {
if (fscanf(in_file, "%c", &dummy) == EOF)
return false;
}
while (dummy != ch);
return true;
}
void vroniObject::HandleBlock(FILE *in_file)
{
int number;
char ch;
double xc, yc, zc;
int i, i1;
if (fscanf(in_file, "%d", &number) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
ch = ParseText(in_file, '(', '[');
if (ch == '[') {
if (FP_fscanf(in_file, "%lf", &xc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
SkipText(in_file, ',');
if (FP_fscanf(in_file, "%lf", &yc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
SkipText(in_file, ',');
if (FP_fscanf(in_file, "%lf", &zc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
#ifdef EXT_APPL_PNTS
i1 = HandlePnt(xc, yc, eap_NIL);
#else
i1 = HandlePnt(xc, yc);
#endif
for (i = 1; i < number; ++i) {
SkipText(in_file, '[');
if (FP_fscanf(in_file, "%lf", &xc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
SkipText(in_file, ',');
if (FP_fscanf(in_file, "%lf", &yc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
SkipText(in_file, ',');
if (FP_fscanf(in_file, "%lf", &zc) == EOF)
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
#ifdef EXT_APPL_SITES
AddSeg(&i1, xc, yc, eas_NIL);
#else
AddSeg(&i1, xc, yc);
#endif
}
}
else if (ch == '(') {
for (i = 0; i < number; ++i) {
SkipText(in_file, '<');
HandleBlock(in_file);
}
}
SkipText(in_file, ')');
return;
}
/* */
/* this is a VERY rudimentary interface for reading Facet_XDR_text_files. */
/* note that this interface is not as general as it ought to be. that is, */
/* likely it will cough on lots of XDR files. i may try to improve it once */
/* i get my hands on a simple description of this format. */
/* */
void vroniObject::ReadXDRFile(char input_file[], vr_bool *new_input)
{
FILE *input;
vr_bool cont = false;
input = OpenFileVD(input_file, "r");
SkipText(input, '[');
SkipText(input, '(');
SkipText(input, '<');
do {
HandleBlock(input);
cont = FindText(input, ',');
if (cont) {
SkipText(input, '(');
SkipText(input, '<');
}
}
while (cont);
fclose(input);
*new_input = true;
return;
}
/* */
/* this is a VERY rudimentary interface for reading ArcInfo export files. */
/* note that this interface is not as general as it ought to be. that is, */
/* likely it will cough on lots of E00 files. i may try to improve it once */
/* i get my hands on a simple description of this format. */
/* */
void vroniObject::ReadE00File(char input_file[], vr_bool *new_input)
{
FILE *input;
char ch[100];
double xc1, yc1, xc2, yc2;
int i, number, version, id, startnode, endnode, lft, rgt, num_vtx;
input = OpenFileVD(input_file, "r");
while (!(EOF == fscanf(input,"%s", ch))) {
if ((ch[0] == 'A') && (ch[1] == 'R') && (ch[2] == 'C')) {
if (EOF == fscanf(input,"%d", &version))
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
break;
}
}
if (EOF == fscanf(input,"%d", &number))
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
while (number != -1) {
if (EOF == fscanf(input,"%d %d %d %d %d %d", &id, &startnode, &endnode,
&lft, &rgt, &num_vtx))
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
if (num_vtx < 2)
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
if (EOF == FP_fscanf(input, "%lf %lf", &xc1, &yc1))
throw std::runtime_error("VRONI error: ReadE00() - premature end of file!");
for (i = 2; i <= num_vtx; ++i) {
if (EOF == FP_fscanf(input, "%lf %lf", &xc2, &yc2))
throw std::runtime_error("VRONI error: ReadE00() - premature end of file!");
#ifdef EXT_APPL_SITES
/* */
/* NIL is used as I don't have any application-specific data; you */
/* may want to add an integer link to some exterior data field that */
/* is to be stored with this segment. */
/* */
HandleSeg(xc1, yc1, xc2, yc2, eas_NIL);
#else
HandleSeg(xc1, yc1, xc2, yc2);
#endif
xc1 = xc2;
yc1 = yc2;
}
if (EOF == fscanf(input,"%d", &number))
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
}
*new_input = true;
fclose(input);
return;
}
/* */
/* This function reads XML arc-to-data in the format */
/* radius 0 0 radius x_center y_center x_target y_target */
/* for a CCW arc, and */
/* radius 0 0 -radius x_center y_center x_target y_target */
/* for a CW arc. The radius is positiv for CCW orientation and negative for */
/* CW orientation. If there is only vertex data in the format */
/* x y */
/* at the current position, then it is returned in xt, yt and r is set to */
/* zero. */
/* A full circle is read in the format */
/* radius 0 0 radius x_center y_center */
/* True is returned, if it was successful. Otherwise, false is returned. */
/* */
/* In type the kind of read data is returned. */
/* 0 for start point, 1 for successive points, 2 for arcs, */
/* 3 for full circle, 4 for the closing seg, 5 path ended correctly */
/* */
vr_bool ReadXMLseg(FILE *input,
double *r, double *xc, double *yc, double *xt, double *yt,
char *type)
{
vr_bool ret;
double xh, yh;
int pos;
char c;
ret = false;
pos = FP_fscanf(input, "%lf %lf 0 %lf %lf %lf %lf %lf",
&xh, &yh, r, xc, yc, xt, yt);
c = fgetc(input);
switch(pos) {
case 0:
if(c == 'h') {
*type = 4;
ret = true;
}
else
*type = 5;
break;
case 2:
*xt = xh;
*r = 0.0;
*type = 1;
*yt = yh;
ret = true;
if(c == 'm')
*type = 0;
else
*type = 1;
break;
case 5:
if(c == 'e') {
*type = 3;
ret = true;
}
break;
case 7:
*type = 2;
ret = true;
break;
default:
break;
}
return ret;
}
/* */
/* add the segment to VRONI's input data */
/* */
void vroniObject::AddXMLseg(int *i1, double_arg xt, double_arg yt,
double_arg xc, double_arg yc, double_arg r,
char type, int i0)
{
int ih;
int orient;
if (r<0)
orient = -ARC;
else
orient = ARC;
switch(type) {
case 0:
#ifdef EXT_APPL_PNTS
*i1 = HandlePnt(xt, yt, eap_NIL);
#else
*i1 = HandlePnt(xt, yt);
#endif
break;
case 1:
#ifdef EXT_APPL_SITES
AddSeg(i1, xt, yt, eas_NIL);
#else
AddSeg(i1, xt, yt);
#endif
break;
case 2:
#ifdef EXT_APPL_SITES
AddArc(i1, xt, yt, xc, yc, orient, eas_NIL);
#else
AddArc(i1, xt, yt, xc, yc, orient);
#endif
break;
case 3:
#ifdef EXT_APPL_PNTS
*i1 = HandlePnt(xc+fabs(r), yc, eap_NIL);
ih = *i1;
#else
*i1 = HandlePnt(xc+r, yc);
ih = *i1;
#endif
#ifdef EXT_APPL_SITES
AddArc(i1, xc, yc+r, xc, yc, orient, eas_NIL);
AddArc(i1, xc-fabs(r), yc, xc, yc, orient, eas_NIL);
AddArc(i1, xc, yc-r, xc, yc, orient, eas_NIL);
CloseArc(*i1, ih, xc, yc, orient, eas_NIL);
#else
AddArc(i1, xc, yc+r, xc, yc, orient);
AddArc(i1, xc-fabs(r), yc, xc, yc, orient);
AddArc(i1, xc, yc-r, xc, yc, orient);
CloseArc(*i1, ih, xc, yc, orient);
#endif
break;
case 4:
/* */
/* close the chain */
/* */
#ifdef EXT_APPL_SITES
CloseSeg(*i1, i0, eas_NIL);
#else
CloseSeg(*i1, i0);
#endif
break;
}
}
vr_bool vroniObject::ReadIpePath(FILE *input)
{
double xc, yc, r, xt, yt;
double a11, a12, a21, a22, vx, vy;
int pos;
int i0 = NIL, i1;
vr_bool ok;
vr_bool tr;
vr_bool arcOrientChange;
char type;
char c;
const char *sstr2[] = {"matrix=\"", ">"};
const char *sstr3[] = {">"};
i1 = NIL;
ok = true;
arcOrientChange = false;
/* read transformation matrix */
switch(fSeeks(input, sstr2, 2)) {
case 1:
pos = FP_fscanf(input, "%lf %lf %lf %lf %lf %lf", &a11, &a21, &a12,
&a22, &vx, &vy);
tr = (pos==6);
if (!tr) {
printf("ReadXML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadXML() - matrix could not be read correctly!");
}
else {
arcOrientChange = ((a12 * a21 - a11 * a22) > 0.0);
}
ok = (fSeeks(input, sstr3, 1) != 0);
break;
case 2:
a11=1.0;
a21=0;
a12=0;
a22=1.0;
vx=0;
vy=0;
tr = false;
ok = true;
break;
default:
tr = false;
ok = (fSeeks(input, sstr3, 1) != 0);
break;
}
while (ok) {
F_NEW_LINE;
ok = ReadXMLseg(input, &r, &xc, &yc, &xt, &yt, &type);
if (ok) {
if (tr) {
if ((type==2) || (type==3))
Transform(&xc, &yc, a11, a21, a12, a22, vx, vy);
Transform(&xt, &yt, a11, a21, a12, a22, vx, vy);
}
if(arcOrientChange)
r = -r;
AddXMLseg(&i1, xt, yt, xc, yc, r, type, i0);
if(type==0) {
i0 = i1;
}
}
else {
if(type!=5) {
printf("ReadXML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadXML() - sub path not read correctly!");
}
}
}
return (i1!=NIL);
}
vr_bool vroniObject::ReadIpeMark(FILE *input)
{
double xt, yt;
double a11, a12, a21, a22, vx, vy;
vr_bool stop;
vr_bool ok;
vr_bool tr;
int pos;
const char *sstr2[] = {"matrix=\"", "pos=\"", ">"};
stop = false;
ok = false;
tr = false;
a11=1.0;
a21=0;
a12=0;
a22=1.0;
vx=0;
vy=0;
while (!stop) {
switch(fSeeks(input, sstr2, 2)) {
case 1:
pos = FP_fscanf(input, "%lf %lf %lf %lf %lf %lf", &a11, &a21, &a12,
&a22, &vx, &vy);
tr = (pos==6);
if (!tr) {
printf("ReadXML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadXML() - matrix could not be read correctly!");
}
break;
case 2:
pos = FP_fscanf(input, "%lf %lf", &xt, &yt);
if (pos==2) {
ok = true;
}
stop = true;
break;
default:
stop = true;
break;
}
}
if (ok) {
if (tr)
Transform(&xt, &yt, a11, a21, a12, a22, vx, vy);
#ifdef EXT_APPL_PNTS
HandlePnt(xt, yt, eap_NIL);
#else
HandlePnt(xt, yt);
#endif
}
else { /* if (ok) */
printf("file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadXML() - Ipe mark not read correctly!");
}
return ok;
}
void vroniObject::ReadXML(char input_file[], vr_bool *new_input)
{
vr_bool ret = false;
char type;
FILE *input;
/* define the search strings */
const char *sstr0[] = {"<page"};
const char *sstr1[] = {"<path","<mark"};
input = OpenFileVD(input_file, "r");
if (input == NULL)
throw std::runtime_error("VRONI error: ReadXML() - input file could not be opened!");
/* Ignore until <page> tag */
if (fSeeks(input, sstr0, 1)) {
while ((type = static_cast<char>(fSeeks(input, sstr1, 2)))) {
switch(type) {
case 1:
ret |= ReadIpePath(input);
break;
case 2:
ret |= ReadIpeMark(input);
break;
default:
break;
}
}
*new_input = ret;
}
fclose(input);
return;
}
vr_bool vroniObject::ReadGraphMLNode(FILE *input)
{
vr_bool stop, x_read, y_read;
double xc, yc;
int pos;
const char *sstr2[] = {"<data key=\"x\">", "<data key=\"y\">"};
stop = false;
x_read = false;
y_read = false;
while (!stop) {
switch(fSeeks(input, sstr2, 2)) {
case 1:
pos = FP_fscanf(input, "%lf", &xc);
if (!(pos == 1)) {
printf("ReadGraphML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadGraphML() - x-coordinate could not be read correctly!");
}
else {
x_read = true;
}
break;
case 2:
pos = FP_fscanf(input, "%lf", &yc);
if (!(pos == 1)) {
printf("ReadGraphML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadGraphML() - y-coordinate could not be read correctly!");
}
else {
y_read = true;
}
default:
stop = true;
break;
}
stop = stop || (x_read && y_read);
}
if (x_read && y_read) {
#ifdef EXT_APPL_PNTS
(void) HandlePnt(xc, yc, eap_NIL);
#else
(void) HandlePnt(xc, yc);
#endif
return true;
}
else {
return false;
}
}
vr_bool vroniObject::ReadGraphMLEdge(FILE *input)
{
vr_bool ok = true;
int i1, i2, i3;
int pos;
pos = FP_fscanf(input, "source=\"%d\" target=\"%d\"", &i1, &i2);
if (!(pos == 2)) {
printf("ReadGraphML(): file position: %ld", ftell(input));
throw std::runtime_error("VRONI error: ReadGraphML() - edge could not be read correctly!");
}
else {
/* */
/* we need to offset the point indices by 2 due to two dummy points */
/* that define the left corners of the bounding box */
/* */
#ifdef EXT_APPL_SITES
i3 = StoreSeg(i1 + 2, i2 + 2, eas_NIL);
#else
i3 = StoreSeg(i1 + 2, i2 + 2);
#endif
#ifdef GRAPHICS
if (graphics) {
AddSegToBuffer(i3, SegColor);
}
#endif
}
return ok;
}
/* */
/* this function reads data of the Salzburg Database in GraphML format. */
/* please note that this function is tailored towards the formatting used by */
/* the Salzburg Database. it is not(!) a general-purpose parser of GraphML */
/* files! */
/* */
void vroniObject::ReadGraphML(char input_file[], vr_bool *new_input)
{
vr_bool ret = false;
char type;
FILE *input;
/* define the search strings */
const char *sstr0[] = {"<graph "};
const char *sstr1[] = {"<node ","<edge "};
input = OpenFileVD(input_file, "r");
if (input == NULL)
throw std::runtime_error("VRONI error: ReadGraphML() - input file could not be opened!");
/* Ignore until <graph> tag */
if (fSeeks(input, sstr0, 1)) {
while ((type = static_cast<char>(fSeeks(input, sstr1, 2)))) {
switch(type) {
case 1:
ret |= ReadGraphMLNode(input);
break;
case 2:
ret |= ReadGraphMLEdge(input);
break;
default:
break;
}
}
*new_input = ret;
}
fclose(input);
return;
}