Added C++ implementation of terrafit, which is about 6x faster!!!
Had to move parts of Terra into a library and into its own namespace, due to conflicts with SimGear definitions.
This commit is contained in:
parent
98c218e22a
commit
61a8fece72
28 changed files with 353 additions and 25 deletions
|
@ -12,3 +12,4 @@ demo_SOURCES = demo.cxx
|
||||||
demo_LDADD = $(support_LIBS) -lz
|
demo_LDADD = $(support_LIBS) -lz
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/Lib
|
INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/Lib
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define MIN(a,b) (((a)>(b))?(b):(a))
|
#define MIN(a,b) (((a)>(b))?(b):(a))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class array {
|
class array {
|
||||||
|
@ -121,4 +122,6 @@ inline T& array2<T>::ref(int i, int j)
|
||||||
return data[j*w + i];
|
return data[j*w + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
typedef double real;
|
typedef double real;
|
||||||
#define EPS 1e-6
|
#define EPS 1e-6
|
||||||
#define EPS2 (EPS*EPS)
|
#define EPS2 (EPS*EPS)
|
||||||
|
@ -20,10 +22,14 @@ typedef int boolean;
|
||||||
enum Axis {X, Y, Z, W};
|
enum Axis {X, Y, Z, W};
|
||||||
enum Side {Left=-1, On=0, Right=1};
|
enum Side {Left=-1, On=0, Right=1};
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "Vec2.h"
|
#include "Vec2.h"
|
||||||
#include "Vec3.h"
|
#include "Vec3.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#define NULL 0
|
#define NULL 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -174,5 +180,6 @@ inline ostream& operator<<(ostream &out, const Line& l)
|
||||||
return out << "Line(a=" << l.a << " b=" << l.b << " c=" << l.c << ")";
|
return out << "Line(a=" << l.a << " b=" << l.b << " c=" << l.c << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,11 +3,14 @@
|
||||||
#include "GreedyInsert.h"
|
#include "GreedyInsert.h"
|
||||||
|
|
||||||
#include "Mask.h"
|
#include "Mask.h"
|
||||||
extern ImportMask *MASK;
|
|
||||||
|
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
|
extern ImportMask *MASK;
|
||||||
|
|
||||||
|
|
||||||
void TrackedTriangle::update(Subdivision& s)
|
void TrackedTriangle::update(Subdivision& s)
|
||||||
{
|
{
|
||||||
|
@ -288,3 +291,5 @@ real GreedySubdivision::eval(int x,int y)
|
||||||
|
|
||||||
return z_plane(x,y);
|
return z_plane(x,y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "Subdivision.h"
|
#include "Subdivision.h"
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class TrackedTriangle : public Triangle
|
class TrackedTriangle : public Triangle
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -89,4 +91,6 @@ public:
|
||||||
#define DATA_POINT_IGNORED 2
|
#define DATA_POINT_IGNORED 2
|
||||||
#define DATA_VALUE_UNKNOWN 3
|
#define DATA_VALUE_UNKNOWN 3
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
void Heap::swap(int i,int j)
|
void Heap::swap(int i,int j)
|
||||||
{
|
{
|
||||||
|
@ -121,3 +122,6 @@ heap_node *Heap::kill(int i)
|
||||||
|
|
||||||
return &ref(size);
|
return &ref(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "Geom.h"
|
#include "Geom.h"
|
||||||
#include "Array.h"
|
#include "Array.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
#define NOT_IN_HEAP -47
|
#define NOT_IN_HEAP -47
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -54,6 +56,6 @@ public:
|
||||||
heap_node *kill(int i);
|
heap_node *kill(int i);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,23 +1,28 @@
|
||||||
EXTRA_DIST = Makefile.gcc-2.95 Makefile.orig
|
EXTRA_DIST = Makefile.gcc-2.95 Makefile.orig
|
||||||
|
|
||||||
# don't build xterra by default
|
# don't build xterra by default
|
||||||
# bin_PROGRAMS = terra xterra
|
#bin_PROGRAMS = terra xterra
|
||||||
bin_PROGRAMS = terra
|
bin_PROGRAMS = terra
|
||||||
|
noinst_LIBRARIES = libTerra.a
|
||||||
|
|
||||||
|
libTerra_a_SOURCES = \
|
||||||
|
Array.h Geom.h \
|
||||||
|
GreedyInsert.cc GreedyInsert.h \
|
||||||
|
Heap.cc Heap.h \
|
||||||
|
Map.cc Map.h \
|
||||||
|
Mask.cc Mask.h \
|
||||||
|
Quadedge.cc Quadedge.h \
|
||||||
|
Subdivision.cc Subdivision.h \
|
||||||
|
Vec2.h Vec3.h
|
||||||
|
|
||||||
terra_SOURCES = \
|
terra_SOURCES = \
|
||||||
Array.h Geom.h GreedyInsert.cc GreedyInsert.h Heap.cc Heap.h \
|
cmdline.cc greedy.cc output.cc terra.cc terra.h version.h
|
||||||
Map.cc Map.h Mask.cc \
|
|
||||||
Mask.h Quadedge.cc Quadedge.h Subdivision.cc Subdivision.h Vec2.h \
|
|
||||||
Vec3.h cmdline.cc greedy.cc \
|
|
||||||
output.cc terra.cc terra.h version.h
|
|
||||||
|
|
||||||
terra_LDADD = $(opengl_LIBS)
|
terra_LDADD = libTerra.a
|
||||||
|
|
||||||
# xterra_SOURCES = \
|
|
||||||
# Array.h Geom.h GreedyInsert.cc GreedyInsert.h Heap.cc Heap.h \
|
#xterra_SOURCES = \
|
||||||
# Map.cc Map.h Mask.cc \
|
# cmdline.cc glHacks.cc glHacks.h greedy.cc gui.cc gui.h \
|
||||||
# Mask.h Quadedge.cc Quadedge.h Subdivision.cc Subdivision.h Vec2.h \
|
|
||||||
# Vec3.h cmdline.cc glHacks.cc glHacks.h greedy.cc gui.cc gui.h \
|
|
||||||
# output.cc terra.h version.h xterra.cc
|
# output.cc terra.h version.h xterra.cc
|
||||||
#
|
#
|
||||||
# xterra_LDADD = $(opengl_LIBS)
|
#xterra_LDADD = $(opengl_LIBS) libTerra.a
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "Geom.h"
|
#include "Geom.h"
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
@ -78,3 +80,5 @@ Map *readPGM(istream& in)
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -8,6 +8,8 @@ using std::istream;
|
||||||
|
|
||||||
#include "Geom.h"
|
#include "Geom.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class Map
|
class Map
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -102,8 +104,6 @@ void DirectMap<T>::textRead(istream& in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
RealMask *readMask(istream& in)
|
RealMask *readMask(istream& in)
|
||||||
{
|
{
|
||||||
|
@ -61,3 +62,5 @@ RealMask *readMask(istream& in)
|
||||||
|
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
using std::istream;
|
using std::istream;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class ImportMask
|
class ImportMask
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -50,4 +52,6 @@ inline real& RealMask::ref(int i, int j)
|
||||||
|
|
||||||
extern RealMask *readMask(istream&);
|
extern RealMask *readMask(istream&);
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
Edge::Edge(const Edge&)
|
Edge::Edge(const Edge&)
|
||||||
{
|
{
|
||||||
cerr << "Edge: Edge assignments are forbidden." << endl;
|
cerr << "Edge: Edge assignments are forbidden." << endl;
|
||||||
|
@ -83,3 +85,6 @@ void splice(Edge *a, Edge *b)
|
||||||
alpha->next = t3;
|
alpha->next = t3;
|
||||||
beta->next = t4;
|
beta->next = t4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "Geom.h"
|
#include "Geom.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class Triangle;
|
class Triangle;
|
||||||
|
|
||||||
class Edge : public Labelled {
|
class Edge : public Labelled {
|
||||||
|
@ -77,4 +79,6 @@ inline ostream& operator<<(ostream& out, const Edge *e)
|
||||||
return out << "{ " << e->Org() << " ---> " << e->Dest() << " }";
|
return out << "{ " << e->Org() << " ---> " << e->Dest() << " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
Edge *Subdivision::makeEdge(Vec2& org, Vec2& dest)
|
Edge *Subdivision::makeEdge(Vec2& org, Vec2& dest)
|
||||||
{
|
{
|
||||||
|
@ -430,3 +431,5 @@ void Triangle::update(Subdivision&)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "Quadedge.h"
|
#include "Quadedge.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class Subdivision;
|
class Subdivision;
|
||||||
|
|
||||||
class Triangle : public Labelled {
|
class Triangle : public Labelled {
|
||||||
|
@ -89,5 +91,6 @@ inline ostream& operator<<(ostream& out, Triangle& t)
|
||||||
<< t.point3() << ")";
|
<< t.point3() << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
using std::istream;
|
using std::istream;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class Vec2 {
|
class Vec2 {
|
||||||
protected:
|
protected:
|
||||||
real elt[2];
|
real elt[2];
|
||||||
|
@ -169,5 +171,6 @@ inline istream& operator>>(istream& in, Vec2& v)
|
||||||
return in >> c >> v[0] >> v[1] >> c;
|
return in >> c >> v[0] >> v[1] >> c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef VEC3_INCLUDED // -*- C++ -*-
|
#ifndef VEC3_INCLUDED // -*- C++ -*-
|
||||||
#define VEC3_INCLUDED
|
#define VEC3_INCLUDED
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
class Vec3 {
|
class Vec3 {
|
||||||
protected:
|
protected:
|
||||||
real elt[3];
|
real elt[3];
|
||||||
|
@ -174,5 +176,6 @@ inline istream& operator>>(istream& in, Vec3& v)
|
||||||
return in >> c >> v[0] >> v[1] >> v[2] >> c;
|
return in >> c >> v[0] >> v[1] >> v[2] >> c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,6 +9,8 @@ using std::cin;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
GreedySubdivision *mesh;
|
GreedySubdivision *mesh;
|
||||||
Map *DEM;
|
Map *DEM;
|
||||||
|
|
||||||
|
@ -187,3 +189,6 @@ void process_cmdline(int argc, char **argv)
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
void scripted_preinsertion(istream& script)
|
void scripted_preinsertion(istream& script)
|
||||||
{
|
{
|
||||||
char op[4];
|
char op[4];
|
||||||
|
@ -109,3 +111,5 @@ void display_greedy_insertion(void (*callback)())
|
||||||
|
|
||||||
announce_goal();
|
announce_goal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
int mesh_view;
|
int mesh_view;
|
||||||
int surf_view;
|
int surf_view;
|
||||||
|
@ -461,3 +462,5 @@ void xglutKeepAspect(float width, float height)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#ifndef GUI_INCLUDED // -*- C++ -*-
|
#ifndef GUI_INCLUDED // -*- C++ -*-
|
||||||
#define GUI_INCLUDED
|
#define GUI_INCLUDED
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
extern int mesh_view;
|
extern int mesh_view;
|
||||||
extern int surf_view;
|
extern int surf_view;
|
||||||
|
|
||||||
extern void gui_init();
|
extern void gui_init();
|
||||||
extern void gui_interact();
|
extern void gui_interact();
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,7 @@ SG_USING_STD(ostream);
|
||||||
SG_USING_STD(ofstream);
|
SG_USING_STD(ofstream);
|
||||||
SG_USING_STD(streampos);
|
SG_USING_STD(streampos);
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
void generate_output(char *filename, FileFormat format)
|
void generate_output(char *filename, FileFormat format)
|
||||||
{
|
{
|
||||||
|
@ -202,3 +203,5 @@ void output_dem(ostream& out)
|
||||||
out << endl;
|
out << endl;
|
||||||
cerr << ">> Done." << endl;
|
cerr << ">> Done." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
process_cmdline(argc, argv);
|
Terra::process_cmdline(argc, argv);
|
||||||
|
|
||||||
greedy_insertion();
|
Terra::greedy_insertion();
|
||||||
|
|
||||||
generate_output();
|
Terra::generate_output();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "Mask.h"
|
#include "Mask.h"
|
||||||
|
|
||||||
|
namespace Terra {
|
||||||
|
|
||||||
extern GreedySubdivision *mesh;
|
extern GreedySubdivision *mesh;
|
||||||
extern Map *DEM;
|
extern Map *DEM;
|
||||||
|
@ -34,5 +35,6 @@ extern void output_dem(ostream&);
|
||||||
|
|
||||||
extern void process_cmdline(int argc, char **argv);
|
extern void process_cmdline(int argc, char **argv);
|
||||||
|
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
glutInit(&argc, argv);
|
glutInit(&argc, argv);
|
||||||
process_cmdline(argc, argv);
|
Terra::process_cmdline(argc, argv);
|
||||||
|
|
||||||
|
|
||||||
gui_init();
|
Terra::gui_init();
|
||||||
|
|
||||||
|
|
||||||
gui_interact();
|
Terra::gui_interact();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
bin_SCRIPTS = terrafit.py
|
bin_SCRIPTS = terrafit.py
|
||||||
|
bin_PROGRAMS = terrafit
|
||||||
|
|
||||||
|
terrafit_SOURCES = terrafit.cc
|
||||||
|
terrafit_LDADD = $(top_builddir)/src/Prep/Terra/libTerra.a \
|
||||||
|
$(top_builddir)/src/Lib/Array/libArray.a \
|
||||||
|
-lsgbucket -lsgstructure -lsgmisc -lsgdebug -lz
|
||||||
|
|
||||||
EXTRA_DIST = terrafit.README terrafit.py.in
|
EXTRA_DIST = terrafit.README terrafit.py.in
|
||||||
|
|
||||||
terrafit.py: $(srcdir)/terrafit.py.in
|
terrafit.py: $(srcdir)/terrafit.py.in
|
||||||
echo ${bindir}
|
echo ${bindir}
|
||||||
sed -e "s%__bindir__%${bindir}%g" $(srcdir)/terrafit.py.in > terrafit.py
|
sed -e "s%__bindir__%${bindir}%g" $(srcdir)/terrafit.py.in > terrafit.py
|
||||||
|
|
||||||
|
INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/Lib
|
||||||
|
|
235
src/Prep/TerraFit/terrafit.cc
Normal file
235
src/Prep/TerraFit/terrafit.cc
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* terrafit.cc - Use Terra as a faster ArrayFit
|
||||||
|
* (see http://graphics.cs.uiuc.edu/~garland/software/terra.html)
|
||||||
|
*
|
||||||
|
* Written by Ralf Gerlich, started December 2007
|
||||||
|
* Based on terrafit.py by Norman Vine
|
||||||
|
* and Terra by Michael Garland
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Ralf Gerlich - http://www.custom-scenery.org/
|
||||||
|
*
|
||||||
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/bucket/newbucket.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
|
||||||
|
#include <Array/array.hxx>
|
||||||
|
|
||||||
|
#include <Prep/Terra/GreedyInsert.h>
|
||||||
|
#include <Prep/Terra/Map.h>
|
||||||
|
#include <Prep/Terra/Mask.h>
|
||||||
|
|
||||||
|
class ArrayMap: public Terra::Map {
|
||||||
|
public:
|
||||||
|
ArrayMap(TGArray& array): array(array) {
|
||||||
|
width=array.get_cols();
|
||||||
|
height=array.get_rows();
|
||||||
|
depth=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Terra::real eval(int i, int j) {
|
||||||
|
return (Terra::real)array.get_array_elev(i,j);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No direct reading of .arr.gz files */
|
||||||
|
virtual void rawRead(istream&) {
|
||||||
|
}
|
||||||
|
virtual void textRead(istream&) {
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
TGArray& array;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Terra::ImportMask default_mask;
|
||||||
|
namespace Terra {
|
||||||
|
/* GreedyInsertion requires us to declare a mask, even if we
|
||||||
|
* don't need one...
|
||||||
|
*/
|
||||||
|
Terra::ImportMask *MASK=&default_mask;
|
||||||
|
}; // namespace Terra
|
||||||
|
|
||||||
|
Terra::real error_threshold=40.0;
|
||||||
|
unsigned int min_points=50;
|
||||||
|
unsigned int point_limit=1000;
|
||||||
|
|
||||||
|
inline int goal_not_met(Terra::GreedySubdivision* mesh)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
( mesh->maxError() > error_threshold &&
|
||||||
|
mesh->pointCount() < point_limit ) ||
|
||||||
|
mesh->pointCount() < min_points;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void announce_goal(Terra::GreedySubdivision* mesh)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Goal conditions met:");
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, " error=" << mesh->maxError() << " [thresh="<< error_threshold << "]");
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, " points=" << mesh->pointCount() << " [limit=" << point_limit << "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void greedy_insertion(Terra::GreedySubdivision* mesh)
|
||||||
|
{
|
||||||
|
|
||||||
|
while( goal_not_met(mesh) )
|
||||||
|
{
|
||||||
|
if( !mesh->greedyInsert() )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
announce_goal(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fit_file(const std::string& path) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO,"Working on file '" << path << "'");
|
||||||
|
|
||||||
|
std::string infile,outfile;
|
||||||
|
if (path.compare(path.size()-7,7,".arr.gz")==0) {
|
||||||
|
infile=path.substr(0,path.size()-7);
|
||||||
|
} else if (path.compare(path.size()-4,4,".arr")==0) {
|
||||||
|
infile=path.substr(0,path.size()-4);
|
||||||
|
} else {
|
||||||
|
/* actually should not happen */
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "unknown input file extension = " << path);
|
||||||
|
throw sg_exception("unknown input file extension!");
|
||||||
|
}
|
||||||
|
|
||||||
|
outfile=infile+".fit.gz";
|
||||||
|
|
||||||
|
struct stat statbuf;
|
||||||
|
if (stat(path.c_str(),&statbuf)!=0) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT ,"ERROR: Unable to stat '" << path << "':" << strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t src_mtime=statbuf.st_mtime;
|
||||||
|
|
||||||
|
if (stat(outfile.c_str(),&statbuf)==0 && statbuf.st_mtime>src_mtime) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO ,"Skipping " << outfile << ", source " << path << " is older");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGBucket bucket(0,0); // dummy bucket
|
||||||
|
TGArray inarray(infile);
|
||||||
|
inarray.parse(bucket);
|
||||||
|
|
||||||
|
ArrayMap *DEM=new ArrayMap(inarray);
|
||||||
|
|
||||||
|
Terra::GreedySubdivision *mesh;
|
||||||
|
|
||||||
|
mesh=new Terra::GreedySubdivision(DEM);
|
||||||
|
|
||||||
|
greedy_insertion(mesh);
|
||||||
|
|
||||||
|
gzFile fp;
|
||||||
|
if ( (fp = gzopen( outfile.c_str(), "wb9" )) == NULL ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: opening " << outfile << " for writing!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x=0;x<DEM->width;x++) {
|
||||||
|
for (int y=0;y<DEM->height;y++) {
|
||||||
|
if (mesh->is_used(x,y) != DATA_POINT_USED)
|
||||||
|
continue;
|
||||||
|
double vx,vy,vz;
|
||||||
|
vx=(inarray.get_originx()+x*inarray.get_col_step())/3600.0;
|
||||||
|
vx=(inarray.get_originy()+y*inarray.get_row_step())/3600.0;
|
||||||
|
vz=DEM->eval(x,y);
|
||||||
|
gzprintf(fp,"%+03.8f %+02.8f %0.2f\n",vx,vy,vz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gzclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void walk_path(const std::string& path) {
|
||||||
|
struct stat statbuf;
|
||||||
|
if (stat(path.c_str(),&statbuf)!=0) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT ,"ERROR: Unable to stat '" << path << "':" << strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.compare(path.size()-7,7,".arr.gz")==0 || path.compare(path.size()-4,4,".arr")==0) {
|
||||||
|
fit_file(path);
|
||||||
|
} else if (S_ISDIR(statbuf.st_mode)) {
|
||||||
|
DIR* dir=opendir(path.c_str());
|
||||||
|
if (!dir) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT ,"ERROR: Unable to open directory '" << path << "':" << strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent* dirent;
|
||||||
|
|
||||||
|
while ((dirent=readdir(dir))) {
|
||||||
|
if (!strcmp(dirent->d_name,".") || !strcmp(dirent->d_name,"..")) {
|
||||||
|
continue; // skip . and ..
|
||||||
|
}
|
||||||
|
SGPath subpath(path);
|
||||||
|
subpath.append(dirent->d_name);
|
||||||
|
walk_path(subpath.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(char* progname, char* msg) {
|
||||||
|
if (msg!=NULL)
|
||||||
|
SG_LOG(SG_GENERAL,SG_ALERT, msg);
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "Usage: " << progname << " [options] <file | path to walk>");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "\t -h | --help ");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "\t -m | --minnodes 50");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "\t -x | --maxnodes 1000");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "\t -e | --maxerror 40");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "\t -v | --version");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "Algorithm will produce at least <minnodes> fitted nodes, but no");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "more than <maxnodes>. Within that range, the algorithm will stop");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "if the maximum elevation error for any remaining point");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "drops below <maxerror> meters.");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "Increasing the maxnodes value and/or decreasing maxerror");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "will produce a better surface approximation.");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "The input file must be a .arr.gz file such as that produced");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "by demchop or hgtchop utils.");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "**** NOTE ****:");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "If a directory is input all .arr.gz files in directory will be");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "processed recursively.");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "The output file(s) is/are called .fit.gz and is simply a list of");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, "from the resulting fitted surface nodes. The user of the");
|
||||||
|
SG_LOG(SG_GENERAL,SG_INFO, ".fit.gz file will need to retriangulate the surface.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
sglog().setLogLevels( SG_ALL, SG_DEBUG );
|
||||||
|
walk_path(argv[1]); // FIXME: parse options
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue