- renamed Polygon library to terragear
- split the new implementation into respective class files (tg_misc is a catch all...)
This commit is contained in:
parent
b1012cd5e9
commit
10db5bfbff
68 changed files with 3350 additions and 3318 deletions
|
@ -25,7 +25,7 @@ add_executable(genapts850
|
|||
)
|
||||
|
||||
target_link_libraries(genapts850
|
||||
Polygon
|
||||
terragear
|
||||
Array
|
||||
${GDAL_LIBRARY}
|
||||
${SIMGEAR_CORE_LIBRARIES}
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
#include <simgear/io/sg_binobj.hxx>
|
||||
#include <simgear/misc/texcoord.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <Polygon/tg_unique_geod.hxx>
|
||||
#include <Polygon/tg_unique_vec3f.hxx>
|
||||
#include <Polygon/tg_unique_vec2f.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_chopper.hxx>
|
||||
#include <terragear/tg_unique_geod.hxx>
|
||||
#include <terragear/tg_unique_vec3f.hxx>
|
||||
#include <terragear/tg_unique_vec2f.hxx>
|
||||
|
||||
#include "airport.hxx"
|
||||
#include "beznode.hxx"
|
||||
|
@ -627,7 +628,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src )
|
|||
for ( unsigned int k = 0; k < rwy_polys.size(); ++k )
|
||||
{
|
||||
tgPolygon poly = rwy_polys[k];
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_pvmt_nodes.get_list() );
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_pvmt_nodes );
|
||||
GENAPT_LOG(SG_GENERAL, SG_DEBUG, "total size after add nodes = " << poly.TotalNodes());
|
||||
rwy_polys[k] = poly;
|
||||
}
|
||||
|
@ -636,7 +637,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src )
|
|||
for ( unsigned int k = 0; k < pvmt_polys.size(); ++k )
|
||||
{
|
||||
tgPolygon poly = pvmt_polys[k];
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_pvmt_nodes.get_list() );
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_pvmt_nodes );
|
||||
GENAPT_LOG(SG_GENERAL, SG_DEBUG, "total size after add nodes = " << poly.TotalNodes());
|
||||
pvmt_polys[k] = poly;
|
||||
}
|
||||
|
@ -645,7 +646,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src )
|
|||
for ( unsigned int k = 0; k < line_polys.size(); ++k )
|
||||
{
|
||||
tgPolygon poly = line_polys[k];
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_feat_nodes.get_list() );
|
||||
poly = tgPolygon::AddColinearNodes( poly, tmp_feat_nodes );
|
||||
GENAPT_LOG(SG_GENERAL, SG_DEBUG, "total size after add nodes = " << poly.TotalNodes());
|
||||
line_polys[k] = poly;
|
||||
}
|
||||
|
@ -673,7 +674,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src )
|
|||
log_time = time(0);
|
||||
GENAPT_LOG( SG_GENERAL, SG_ALERT, "Finished cleaning polys for " << icao << " at " << DebugTimeToString(log_time) );
|
||||
|
||||
base_poly = tgPolygon::AddColinearNodes( base_poly, tmp_pvmt_nodes.get_list() );
|
||||
base_poly = tgPolygon::AddColinearNodes( base_poly, tmp_pvmt_nodes );
|
||||
base_poly = tgPolygon::Snap( base_poly, gSnap );
|
||||
|
||||
// Finally find slivers in base
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _APT_MATH_HXX_
|
||||
#define _APT_MATH_HXX_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
tgContour gen_wgs84_area( SGGeod origin,
|
||||
double length_m,
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "global.hxx"
|
||||
#include "beznode.hxx"
|
||||
|
@ -455,7 +456,7 @@ int ClosedPoly::BuildBtg( tgpolygon_list& rwy_polys, tgcontour_list& slivers, tg
|
|||
if ( is_pavement && pre_tess.Contours() )
|
||||
{
|
||||
if( shapefile_name.size() ) {
|
||||
tgPolygon::ToShapefile( pre_tess, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( pre_tess, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
accum.ToShapefiles( "./airport_dbg", "accum" );
|
||||
}
|
||||
|
||||
|
@ -463,7 +464,7 @@ int ClosedPoly::BuildBtg( tgpolygon_list& rwy_polys, tgcontour_list& slivers, tg
|
|||
|
||||
if ( clipped.Contours() ) {
|
||||
if( shapefile_name.size() ) {
|
||||
tgPolygon::ToShapefile( clipped, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( clipped, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
}
|
||||
|
||||
tgPolygon::RemoveSlivers( clipped, slivers );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _BEZPOLY_H_
|
||||
#define _BEZPOLY_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
#include "beznode.hxx"
|
||||
#include "linearfeature.hxx"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <Polygon/surface.hxx>
|
||||
#include <terragear/tg_surface.hxx>
|
||||
|
||||
// lookup node elevations for each point in the SGGeod list. Returns
|
||||
// average of all points. Doesn't modify the original list.
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
#ifndef _HELIPAD_HXX
|
||||
#define _HELIPAD_HXX
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_accumulator.hxx>
|
||||
#include <terragear/tg_light.hxx>
|
||||
|
||||
class Helipad
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef _LINEARFEATURE_H_
|
||||
#define _LINEARFEATURE_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_accumulator.hxx>
|
||||
#include <terragear/tg_light.hxx>
|
||||
#include "beznode.hxx"
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _LINKED_OBJECTS_H_
|
||||
#define _LINKED_OBJECTS_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
class Windsock
|
||||
{
|
||||
|
|
|
@ -301,9 +301,6 @@ int main(int argc, char **argv)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
// Initialize shapefile support (for debugging)
|
||||
tgShapefile::Init();
|
||||
|
||||
sg_gzifstream in( input_file );
|
||||
if ( !in.is_open() )
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifndef _OBJECT_H_
|
||||
#define _OBJECT_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_light.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
class LightingObj
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/math/SGGeodesy.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
#include "global.hxx"
|
||||
#include "apt_math.hxx"
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef _RUNWAY_H_
|
||||
#define _RUNWAY_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_accumulator.hxx>
|
||||
#include <terragear/tg_light.hxx>
|
||||
|
||||
#include "apt_math.hxx"
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
@ -26,12 +28,12 @@
|
|||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "global.hxx"
|
||||
#include "beznode.hxx"
|
||||
#include "runway.hxx"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
using std::string;
|
||||
struct sections
|
||||
{
|
||||
|
@ -301,14 +303,14 @@ void Runway::gen_runway_section( const tgPolygon& runway,
|
|||
GENAPT_LOG(SG_GENERAL, SG_DEBUG, section );
|
||||
|
||||
if( shapefile_name.size() ) {
|
||||
tgPolygon::ToShapefile( section, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( section, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
}
|
||||
|
||||
// Clip the new polygon against what ever has already been created.
|
||||
tgPolygon clipped = accum.Diff( section );
|
||||
|
||||
if( shapefile_name.size() ) {
|
||||
tgPolygon::ToShapefile( clipped, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( clipped, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
}
|
||||
|
||||
tgPolygon::RemoveSlivers( clipped, slivers );
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGQueue.hxx>
|
||||
#include <Polygon/rectangle.hxx>
|
||||
#include <terragear/tg_rectangle.hxx>
|
||||
#include "airport.hxx"
|
||||
|
||||
#define P_STATE_INIT (0)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "global.hxx"
|
||||
#include "apt_math.hxx"
|
||||
#include "beznode.hxx"
|
||||
|
@ -135,7 +137,7 @@ int Taxiway::BuildBtg( tgpolygon_list& rwy_polys, tglightcontour_list& rwy_light
|
|||
tgPolygon taxi_poly;
|
||||
taxi_poly.AddContour( taxi_contour );
|
||||
|
||||
tgPolygon::ToShapefile( taxi_poly, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( taxi_poly, "./airport_dbg", std::string("preclip"), shapefile_name );
|
||||
accum.ToShapefiles( "./airport_dbg", "accum" );
|
||||
}
|
||||
|
||||
|
@ -151,7 +153,7 @@ int Taxiway::BuildBtg( tgpolygon_list& rwy_polys, tglightcontour_list& rwy_light
|
|||
rwy_polys.push_back( split );
|
||||
|
||||
if( shapefile_name.size() ) {
|
||||
tgPolygon::ToShapefile( split, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
tgShapefile::FromPolygon( split, "./airport_dbg", std::string("postclip"), shapefile_name );
|
||||
}
|
||||
|
||||
accum.Add( taxi_contour );
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef _TAXIWAY_H_
|
||||
#define _TAXIWAY_H_
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_light.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_accumulator.hxx>
|
||||
|
||||
#include "apt_math.hxx"
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ set_target_properties(tg-construct PROPERTIES
|
|||
"DEFAULT_USGS_MAPFILE=\"${PKGDATADIR}/usgsmap.txt\";DEFAULT_PRIORITIES_FILE=\"${PKGDATADIR}/default_priorities.txt\"" )
|
||||
|
||||
target_link_libraries(tg-construct
|
||||
Polygon
|
||||
terragear
|
||||
Array landcover
|
||||
${Boost_LIBRARIES}
|
||||
${GDAL_LIBRARY}
|
||||
|
@ -43,7 +43,7 @@ add_executable(cliptst
|
|||
cliptst.cxx)
|
||||
|
||||
target_link_libraries(cliptst
|
||||
Polygon
|
||||
terragear
|
||||
${GDAL_LIBRARY}
|
||||
${SIMGEAR_CORE_LIBRARIES}
|
||||
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include <Polygon/clipper.hpp>
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/clipper.hpp>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
@ -259,9 +260,8 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
|
||||
if (show_svg) {
|
||||
tgShapefile::Init();
|
||||
clipper_to_shapefile( subject, "./clptst_subject" );
|
||||
clipper_to_shapefile( clip, "./clptst_clip" );
|
||||
tgShapefile::FromClipper( subject, "./clptst_subject", "subject", "subject" );
|
||||
tgShapefile::FromClipper( clip, "./clptst_clip", "clip", "clip" );
|
||||
}
|
||||
|
||||
ClipType clipType;
|
||||
|
@ -315,7 +315,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if( show_svg ) {
|
||||
cout << "Generating shapefile\n";
|
||||
clipper_to_shapefile( solution, "./clptst_solution" );
|
||||
tgShapefile::FromClipper( solution, "./clptst_solution", "solution", "solution" );
|
||||
}
|
||||
} else
|
||||
cout << "failed.\n\n";
|
||||
|
|
|
@ -71,9 +71,6 @@ int main(int argc, char **argv) {
|
|||
|
||||
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||
|
||||
// Initialize shapefile support (for debugging)
|
||||
tgShapefile::Init();
|
||||
|
||||
//
|
||||
// Parse the command-line arguments.
|
||||
//
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#define TG_MAX_AREA_TYPES 128
|
||||
|
||||
#include <Array/array.hxx>
|
||||
#include <Polygon/tg_nodes.hxx>
|
||||
#include <terragear//tg_nodes.hxx>
|
||||
#include <landcover/landcover.hxx>
|
||||
|
||||
#include "tglandclass.hxx"
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <simgear/compiler.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "tgconstruct.hxx"
|
||||
|
||||
void TGConstruct::FixTJunctions( void ) {
|
||||
|
@ -86,21 +88,21 @@ void TGConstruct::CleanClippedPolys() {
|
|||
poly = tgPolygon::Snap(poly, gSnap);
|
||||
|
||||
if ( IsDebugShape( poly.GetId() ) ) {
|
||||
tgPolygon::ToShapefile( poly, ds_name, "snapped", "" );
|
||||
tgShapefile::FromPolygon( poly, ds_name, "snapped", "" );
|
||||
}
|
||||
|
||||
// step 2 : remove_dups
|
||||
poly = tgPolygon::RemoveDups( poly );
|
||||
|
||||
if ( IsDebugShape( poly.GetId() ) ) {
|
||||
tgPolygon::ToShapefile( poly, ds_name, "rem_dups", "" );
|
||||
tgShapefile::FromPolygon( poly, ds_name, "rem_dups", "" );
|
||||
}
|
||||
|
||||
// step 3 : remove_bad_contours
|
||||
poly = tgPolygon::RemoveBadContours( poly );
|
||||
|
||||
if ( IsDebugShape( poly.GetId() ) ) {
|
||||
tgPolygon::ToShapefile( poly, ds_name, "rem_bcs", "" );
|
||||
tgShapefile::FromPolygon( poly, ds_name, "rem_bcs", "" );
|
||||
}
|
||||
|
||||
polys_clipped.set_poly(area, p, poly);
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <terragear/tg_accumulator.hxx>
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "tgconstruct.hxx"
|
||||
|
||||
using std::string;
|
||||
|
@ -97,9 +100,9 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
|
||||
// Dump the masks
|
||||
if ( debug_all || debug_shapes.size() || debug_areas.size() ) {
|
||||
tgPolygon::ToShapefile( land_mask, ds_name, "land_mask", "" );
|
||||
tgPolygon::ToShapefile( water_mask, ds_name, "water_mask", "" );
|
||||
tgPolygon::ToShapefile( island_mask, ds_name, "island_mask", "" );
|
||||
tgShapefile::FromPolygon( land_mask, ds_name, "land_mask", "" );
|
||||
tgShapefile::FromPolygon( water_mask, ds_name, "water_mask", "" );
|
||||
tgShapefile::FromPolygon( island_mask, ds_name, "island_mask", "" );
|
||||
}
|
||||
|
||||
// process polygons in priority order
|
||||
|
@ -130,7 +133,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
|
||||
sprintf(layer, "pre_clip_%d", polys_in.get_poly( i, j ).GetId() );
|
||||
sprintf(name, "shape %d,%d", i,j);
|
||||
tgPolygon::ToShapefile( tmp, ds_name, layer, name );
|
||||
tgShapefile::FromPolygon( tmp, ds_name, layer, name );
|
||||
|
||||
sprintf(layer, "pre_clip_accum_%d_%d", accum_idx, polys_in.get_poly( i, j ).GetId() );
|
||||
accum.ToShapefiles( ds_name, layer );
|
||||
|
@ -145,7 +148,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
sprintf(layer, "post_clip_%d", polys_in.get_poly( i, j ).GetId() );
|
||||
sprintf(name, "shape %d,%d", i,j);
|
||||
|
||||
tgPolygon::ToShapefile( clipped, ds_name, layer, name );
|
||||
tgShapefile::FromPolygon( clipped, ds_name, layer, name );
|
||||
}
|
||||
|
||||
// only add to output list if the clip left us with a polygon
|
||||
|
@ -190,7 +193,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
char name[32];
|
||||
for ( unsigned int i=0; i<slivers.size(); i++ ) {
|
||||
sprintf( name, "sliver %4d", i );
|
||||
tgContour::ToShapefile( slivers[i], ds_name, "slivers", name );
|
||||
tgShapefile::FromContour( slivers[i], ds_name, "slivers", name );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -219,7 +222,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
char name[32];
|
||||
for ( unsigned int i=0; i<slivers.size(); i++ ) {
|
||||
sprintf( name, "sliver %4d", i );
|
||||
tgContour::ToShapefile( slivers[i], ds_name, "remains slivers", name );
|
||||
tgShapefile::FromContour( slivers[i], ds_name, "remains slivers", name );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <Polygon/tg_unique_vec3f.hxx>
|
||||
#include <Polygon/tg_unique_vec2f.hxx>
|
||||
#include <terragear/tg_unique_vec3f.hxx>
|
||||
#include <terragear/tg_unique_vec2f.hxx>
|
||||
|
||||
#include "tgconstruct.hxx"
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
#include "tgconstruct.hxx"
|
||||
|
||||
void TGConstruct::TesselatePolys( void )
|
||||
|
@ -40,7 +42,7 @@ void TGConstruct::TesselatePolys( void )
|
|||
tgPolygon poly = polys_clipped.get_poly(area, p );
|
||||
|
||||
if ( IsDebugShape( poly.GetId() ) ) {
|
||||
tgPolygon::ToShapefile( poly, ds_name, "preteselate", "" );
|
||||
tgShapefile::FromPolygon( poly, ds_name, "preteselate", "" );
|
||||
}
|
||||
|
||||
tgRectangle rect = poly.GetBoundingBox();
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <simgear/math/sg_types.hxx>
|
||||
#include <simgear/io/lowlevel.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
#define TG_MAX_AREA_TYPES 128
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@ include_directories(${PROJECT_SOURCE_DIR}/src/Lib)
|
|||
add_subdirectory(Array)
|
||||
add_subdirectory(DEM)
|
||||
add_subdirectory(HGT)
|
||||
add_subdirectory(Polygon)
|
||||
add_subdirectory(landcover)
|
||||
add_subdirectory(terragear)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
add_library(Polygon STATIC
|
||||
clipper.cpp
|
||||
clipper.hpp
|
||||
polygon.cxx
|
||||
polygon.hxx
|
||||
rectangle.cxx
|
||||
rectangle.hxx
|
||||
surface.cxx
|
||||
surface.hxx
|
||||
tg_nodes.cxx
|
||||
tg_nodes.hxx
|
||||
tg_unique_geod.hxx
|
||||
tg_unique_tgnode.hxx
|
||||
tg_unique_vec2f.hxx
|
||||
tg_unique_vec3d.hxx
|
||||
tg_unique_vec3f.hxx
|
||||
)
|
File diff suppressed because it is too large
Load diff
35
src/Lib/terragear/CMakeLists.txt
Normal file
35
src/Lib/terragear/CMakeLists.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
include_directories(${GDAL_INCLUDE_DIR})
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
add_library(terragear STATIC
|
||||
clipper.cpp
|
||||
clipper.hpp
|
||||
tg_accumulator.cxx
|
||||
tg_accumulator.hxx
|
||||
tg_chopper.cxx
|
||||
tg_chopper.hxx
|
||||
tg_contour.cxx
|
||||
tg_contour.hxx
|
||||
tg_light.hxx
|
||||
tg_misc.cxx
|
||||
tg_misc.hxx
|
||||
tg_nodes.cxx
|
||||
tg_nodes.hxx
|
||||
tg_polygon.cxx
|
||||
tg_polygon.hxx
|
||||
tg_polygon_clean.cxx
|
||||
tg_polygon_clip.cxx
|
||||
tg_polygon_tesselate.cxx
|
||||
tg_rectangle.cxx
|
||||
tg_rectangle.hxx
|
||||
tg_shapefile.cxx
|
||||
tg_shapefile.hxx
|
||||
tg_surface.cxx
|
||||
tg_surface.hxx
|
||||
tg_unique_geod.hxx
|
||||
tg_unique_tgnode.hxx
|
||||
tg_unique_vec2f.hxx
|
||||
tg_unique_vec3d.hxx
|
||||
tg_unique_vec3f.hxx
|
||||
)
|
131
src/Lib/terragear/tg_accumulator.cxx
Normal file
131
src/Lib/terragear/tg_accumulator.cxx
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_accumulator.hxx"
|
||||
#include "tg_shapefile.hxx"
|
||||
#include "tg_misc.hxx"
|
||||
|
||||
tgPolygon tgAccumulator::Diff( const tgContour& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); ++i ) {
|
||||
all_nodes.add( subject.GetNode(i) );
|
||||
}
|
||||
|
||||
unsigned int num_hits = 0;
|
||||
tgRectangle box1 = subject.GetBoundingBox();
|
||||
|
||||
ClipperLib::Polygon clipper_subject = tgContour::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
|
||||
c.AddPolygon(clipper_subject, ClipperLib::ptSubject);
|
||||
|
||||
// clip result against all polygons in the accum that intersect our bb
|
||||
for (unsigned int i=0; i < accum.size(); i++) {
|
||||
tgRectangle box2 = BoundingBox_FromClipper( accum[i] );
|
||||
|
||||
if ( box2.intersects(box1) )
|
||||
{
|
||||
c.AddPolygons(accum[i], ClipperLib::ptClip);
|
||||
num_hits++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_hits) {
|
||||
if ( !c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftNonZero, ClipperLib::pftNonZero) ) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Diff With Accumulator returned FALSE" );
|
||||
exit(-1);
|
||||
}
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
} else {
|
||||
result.AddContour( subject );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tgAccumulator::Add( const tgContour& subject )
|
||||
{
|
||||
tgPolygon poly;
|
||||
poly.AddContour( subject );
|
||||
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( poly );
|
||||
accum.push_back( clipper_subject );
|
||||
}
|
||||
|
||||
void tgAccumulator::ToShapefiles( const std::string& path, const std::string& layer_prefix )
|
||||
{
|
||||
char shapefile[16];
|
||||
char layer[16];
|
||||
|
||||
for (unsigned int i=0; i < accum.size(); i++) {
|
||||
sprintf( layer, "%s_%d", layer_prefix.c_str(), i );
|
||||
sprintf( shapefile, "accum_%d", i );
|
||||
tgShapefile::FromClipper( accum[i], path, layer, std::string(shapefile) );
|
||||
}
|
||||
}
|
||||
|
||||
tgPolygon tgAccumulator::Diff( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int num_hits = 0;
|
||||
tgRectangle box1 = subject.GetBoundingBox();
|
||||
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
|
||||
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
|
||||
|
||||
// clip result against all polygons in the accum that intersect our bb
|
||||
for (unsigned int i=0; i < accum.size(); i++) {
|
||||
tgRectangle box2 = BoundingBox_FromClipper( accum[i] );
|
||||
|
||||
if ( box2.intersects(box1) )
|
||||
{
|
||||
c.AddPolygons(accum[i], ClipperLib::ptClip);
|
||||
num_hits++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_hits) {
|
||||
if ( !c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftNonZero, ClipperLib::pftNonZero) ) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Diff With Accumulator returned FALSE" );
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
// Make sure we keep texturing info
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
} else {
|
||||
result = subject;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tgAccumulator::Add( const tgPolygon& subject )
|
||||
{
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( subject );
|
||||
accum.push_back( clipper_subject );
|
||||
}
|
25
src/Lib/terragear/tg_accumulator.hxx
Normal file
25
src/Lib/terragear/tg_accumulator.hxx
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef _TGACCUMULATOR_HXX
|
||||
#define _TGACCUMULATOR_HXX
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
#include "tg_contour.hxx"
|
||||
#include "clipper.hpp"
|
||||
|
||||
class tgAccumulator
|
||||
{
|
||||
public:
|
||||
tgPolygon Diff( const tgContour& subject );
|
||||
tgPolygon Diff( const tgPolygon& subject );
|
||||
|
||||
void Add( const tgContour& subject );
|
||||
void Add( const tgPolygon& subject );
|
||||
|
||||
void ToShapefiles( const std::string& path, const std::string& layer );
|
||||
|
||||
private:
|
||||
typedef std::vector < ClipperLib::Polygons > clipper_polygons_list;
|
||||
|
||||
clipper_polygons_list accum;
|
||||
};
|
||||
|
||||
#endif // _TGACCUMULATOR_HXX
|
274
src/Lib/terragear/tg_chopper.cxx
Normal file
274
src/Lib/terragear/tg_chopper.cxx
Normal file
|
@ -0,0 +1,274 @@
|
|||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/io/lowlevel.hxx>
|
||||
|
||||
|
||||
#include "tg_chopper.hxx"
|
||||
|
||||
void tgChopper::Clip( const tgPolygon& subject,
|
||||
const std::string& type,
|
||||
SGBucket& b )
|
||||
{
|
||||
// p;
|
||||
|
||||
SGGeod min, max;
|
||||
SGGeod c = b.get_center();
|
||||
double span = b.get_width();
|
||||
tgPolygon base, result;
|
||||
|
||||
// calculate bucket dimensions
|
||||
if ( (c.getLatitudeDeg() >= -89.0) && (c.getLatitudeDeg() < 89.0) ) {
|
||||
min = SGGeod::fromDeg( c.getLongitudeDeg() - span/2.0, c.getLatitudeDeg() - SG_HALF_BUCKET_SPAN );
|
||||
max = SGGeod::fromDeg( c.getLongitudeDeg() + span/2.0, c.getLatitudeDeg() + SG_HALF_BUCKET_SPAN );
|
||||
} else if ( c.getLatitudeDeg() < -89.0) {
|
||||
min = SGGeod::fromDeg( -90.0, -180.0 );
|
||||
max = SGGeod::fromDeg( -89.0, 180.0 );
|
||||
} else if ( c.getLatitudeDeg() >= 89.0) {
|
||||
min = SGGeod::fromDeg( 89.0, -180.0 );
|
||||
max = SGGeod::fromDeg( 90.0, 180.0 );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Out of range latitude in clip_and_write_poly() = " << c.getLatitudeDeg() );
|
||||
}
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " (" << min << ") (" << max << ")" );
|
||||
|
||||
// set up clipping tile
|
||||
base.AddNode( 0, SGGeod::fromDeg( min.getLongitudeDeg(), min.getLatitudeDeg()) );
|
||||
base.AddNode( 0, SGGeod::fromDeg( max.getLongitudeDeg(), min.getLatitudeDeg()) );
|
||||
base.AddNode( 0, SGGeod::fromDeg( max.getLongitudeDeg(), max.getLatitudeDeg()) );
|
||||
base.AddNode( 0, SGGeod::fromDeg( min.getLongitudeDeg(), max.getLatitudeDeg()) );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "shape contours = " << subject.Contours() );
|
||||
for ( unsigned int ii = 0; ii < subject.Contours(); ii++ ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " hole = " << subject.GetContour(ii).GetHole() );
|
||||
}
|
||||
|
||||
result = tgPolygon::Intersect( subject, base );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "result contours = " << result.Contours() );
|
||||
for ( unsigned int ii = 0; ii < result.Contours(); ii++ ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " hole = " << result.GetContour(ii).GetHole() );
|
||||
}
|
||||
|
||||
if ( subject.GetPreserve3D() ) {
|
||||
result.InheritElevations( subject );
|
||||
}
|
||||
|
||||
if ( result.Contours() > 0 ) {
|
||||
result.SetPreserve3D( subject.GetPreserve3D() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
if ( subject.GetTexMethod() == TG_TEX_BY_GEODE ) {
|
||||
// need to set center latitude for geodetic texturing
|
||||
result.SetTexMethod( TG_TEX_BY_GEODE, b.get_center_lat() );
|
||||
}
|
||||
result.SetFlag(type);
|
||||
|
||||
lock.lock();
|
||||
bp_map[b.gen_index()].push_back( result );
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void tgChopper::Add( const tgPolygon& subject, const std::string& type )
|
||||
{
|
||||
tgRectangle bb;
|
||||
SGGeod p;
|
||||
|
||||
// bail out immediately if polygon is empty
|
||||
if ( subject.Contours() == 0 )
|
||||
return;
|
||||
|
||||
bb = subject.GetBoundingBox();
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " min = " << bb.getMin() << " max = " << bb.getMax() );
|
||||
|
||||
// find buckets for min, and max points of convex hull.
|
||||
// note to self: self, you should think about checking for
|
||||
// polygons that span the date line
|
||||
SGBucket b_min( bb.getMin() );
|
||||
SGBucket b_max( bb.getMax() );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " Bucket min = " << b_min );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " Bucket max = " << b_max );
|
||||
|
||||
if ( b_min == b_max ) {
|
||||
// shape entirely contained in a single bucket, write and bail
|
||||
Clip( subject, type, b_min );
|
||||
return;
|
||||
}
|
||||
|
||||
SGBucket b_cur;
|
||||
int dx, dy;
|
||||
|
||||
sgBucketDiff(b_min, b_max, &dx, &dy);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " polygon spans tile boundaries" );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " dx = " << dx << " dy = " << dy );
|
||||
|
||||
if ( (dx > 2880) || (dy > 1440) )
|
||||
throw sg_exception("something is really wrong in split_polygon()!!!!");
|
||||
|
||||
if ( dy <= 1 ) {
|
||||
// we are down to at most two rows, write each column and then bail
|
||||
double min_center_lat = b_min.get_center_lat();
|
||||
double min_center_lon = b_min.get_center_lon();
|
||||
for ( int j = 0; j <= dy; ++j ) {
|
||||
for ( int i = 0; i <= dx; ++i ) {
|
||||
b_cur = sgBucketOffset(min_center_lon, min_center_lat, i, j);
|
||||
Clip( subject, type, b_cur );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// we have two or more rows left, split in half (along a
|
||||
// horizontal dividing line) and recurse with each half
|
||||
|
||||
// find mid point (integer math)
|
||||
int mid = (dy + 1) / 2 - 1;
|
||||
|
||||
// determine horizontal clip line
|
||||
SGBucket b_clip = sgBucketOffset( bb.getMin().getLongitudeDeg(), bb.getMin().getLatitudeDeg(), 0, mid);
|
||||
double clip_line = b_clip.get_center_lat();
|
||||
if ( (clip_line >= -90.0 + SG_HALF_BUCKET_SPAN)
|
||||
&& (clip_line < 90.0 - SG_HALF_BUCKET_SPAN) )
|
||||
clip_line += SG_HALF_BUCKET_SPAN;
|
||||
else if ( clip_line < -89.0 )
|
||||
clip_line = -89.0;
|
||||
else if ( clip_line >= 89.0 )
|
||||
clip_line = 90.0;
|
||||
else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Out of range latitude in clip_and_write_poly() = " << clip_line );
|
||||
}
|
||||
|
||||
{
|
||||
//
|
||||
// Crop bottom area (hopefully by putting this in it's own
|
||||
// scope we can shorten the life of some really large data
|
||||
// structures to reduce memory use)
|
||||
//
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Generating bottom half (" << bb.getMin().getLatitudeDeg() << "-" << clip_line << ")" );
|
||||
|
||||
tgPolygon bottom, bottom_clip;
|
||||
|
||||
bottom.AddNode( 0, SGGeod::fromDeg(-180.0, bb.getMin().getLatitudeDeg()) );
|
||||
bottom.AddNode( 0, SGGeod::fromDeg( 180.0, bb.getMin().getLatitudeDeg()) );
|
||||
bottom.AddNode( 0, SGGeod::fromDeg( 180.0, clip_line) );
|
||||
bottom.AddNode( 0, SGGeod::fromDeg(-180.0, clip_line) );
|
||||
|
||||
bottom_clip = tgPolygon::Intersect( subject, bottom );
|
||||
|
||||
// the texparam should be constant over each clipped poly.
|
||||
// when they are reassembled, we want the texture map to
|
||||
// be seamless
|
||||
Add( bottom_clip, type );
|
||||
}
|
||||
|
||||
{
|
||||
//
|
||||
// Crop top area (hopefully by putting this in it's own scope
|
||||
// we can shorten the life of some really large data
|
||||
// structures to reduce memory use)
|
||||
//
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Generating top half (" << clip_line << "-" << bb.getMax().getLatitudeDeg() << ")" );
|
||||
|
||||
tgPolygon top, top_clip;
|
||||
|
||||
top.AddNode( 0, SGGeod::fromDeg(-180.0, clip_line) );
|
||||
top.AddNode( 0, SGGeod::fromDeg( 180.0, clip_line) );
|
||||
top.AddNode( 0, SGGeod::fromDeg( 180.0, bb.getMax().getLatitudeDeg()) );
|
||||
top.AddNode( 0, SGGeod::fromDeg(-180.0, bb.getMax().getLatitudeDeg()) );
|
||||
|
||||
top_clip = tgPolygon::Intersect( subject, top );
|
||||
|
||||
if ( top_clip.TotalNodes() == subject.TotalNodes() ) {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Generating top half - total nodes is the same after clip" << subject.TotalNodes() );
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Add( top_clip, type );
|
||||
}
|
||||
}
|
||||
|
||||
long int tgChopper::GenerateIndex( std::string path )
|
||||
{
|
||||
std::string index_file = path + "/chop.idx";
|
||||
long int index = 0;
|
||||
|
||||
//Open or create the named mutex
|
||||
boost::interprocess::named_mutex mutex(boost::interprocess::open_or_create, "tgChopper_index2");
|
||||
{
|
||||
// SG_LOG(SG_GENERAL, SG_ALERT, "getting lock");
|
||||
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(mutex);
|
||||
// SG_LOG(SG_GENERAL, SG_ALERT, " - got it");
|
||||
|
||||
/* first try to read the file */
|
||||
FILE *fp = fopen( index_file.c_str(), "r+" );
|
||||
if ( fp == NULL ) {
|
||||
/* doesn't exist - create it */
|
||||
fp = fopen( index_file.c_str(), "w" );
|
||||
if ( fp == NULL ) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Error cannot open Index file " << index_file << " for writing");
|
||||
boost::interprocess::named_mutex::remove("tgChopper_index2");
|
||||
exit( 0 );
|
||||
}
|
||||
} else {
|
||||
fread( (void*)&index, sizeof(long int), 1, fp );
|
||||
// SG_LOG(SG_GENERAL, SG_ALERT, " SUCCESS READING INDEX FILE - READ INDEX " << index );
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
rewind( fp );
|
||||
fwrite( (void*)&index, sizeof(long int), 1, fp );
|
||||
fclose( fp );
|
||||
}
|
||||
|
||||
boost::interprocess::named_mutex::remove("tgChopper_index2");
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void tgChopper::Save( void )
|
||||
{
|
||||
// traverse the bucket list
|
||||
bucket_polys_map_interator it;
|
||||
char tile_name[16];
|
||||
char poly_ext[16];
|
||||
|
||||
for (it=bp_map.begin(); it != bp_map.end(); it++) {
|
||||
SGBucket b( (*it).first );
|
||||
tgpolygon_list const& polys = (*it).second;
|
||||
|
||||
std::string path = root_path + "/" + b.gen_base_path();
|
||||
sprintf( tile_name, "%ld", b.gen_index() );
|
||||
|
||||
std::string polyfile = path + "/" + tile_name;
|
||||
|
||||
SGPath sgp( polyfile );
|
||||
sgp.create_dir( 0755 );
|
||||
|
||||
long int poly_index = GenerateIndex( path );
|
||||
|
||||
sprintf( poly_ext, "%ld", poly_index );
|
||||
polyfile = polyfile + "." + poly_ext;
|
||||
|
||||
gzFile fp;
|
||||
if ( (fp = gzopen( polyfile.c_str(), "wb9" )) == NULL ) {
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "ERROR: opening " << polyfile.c_str() << " for writing!" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write polys to the file */
|
||||
sgWriteUInt( fp, polys.size() );
|
||||
for ( unsigned int i=0; i<polys.size(); i++ ) {
|
||||
polys[i].SaveToGzFile( fp );
|
||||
}
|
||||
|
||||
gzclose( fp );
|
||||
}
|
||||
}
|
27
src/Lib/terragear/tg_chopper.hxx
Normal file
27
src/Lib/terragear/tg_chopper.hxx
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <map>
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
// for ogr-decode : generate a bunch of polygons, mapped by bucket id
|
||||
typedef std::map<long int, tgpolygon_list> bucket_polys_map;
|
||||
typedef bucket_polys_map::iterator bucket_polys_map_interator;
|
||||
|
||||
class tgChopper
|
||||
{
|
||||
public:
|
||||
tgChopper( const std::string& path ) {
|
||||
root_path = path;
|
||||
}
|
||||
|
||||
void Add( const tgPolygon& poly, const std::string& type );
|
||||
void Save( void );
|
||||
|
||||
private:
|
||||
long int GenerateIndex( std::string path );
|
||||
void Clip( const tgPolygon& subject, const std::string& type, SGBucket& b );
|
||||
void Chop( const tgPolygon& subject, const std::string& type );
|
||||
|
||||
std::string root_path;
|
||||
bucket_polys_map bp_map;
|
||||
SGMutex lock;
|
||||
};
|
855
src/Lib/terragear/tg_contour.cxx
Normal file
855
src/Lib/terragear/tg_contour.cxx
Normal file
|
@ -0,0 +1,855 @@
|
|||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/io/lowlevel.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_misc.hxx"
|
||||
#include "tg_accumulator.hxx"
|
||||
#include "tg_contour.hxx"
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
tgContour tgContour::Snap( const tgContour& subject, double snap )
|
||||
{
|
||||
tgContour result;
|
||||
SGGeod pt;
|
||||
|
||||
for (unsigned int i = 0; i < subject.GetSize(); i++) {
|
||||
pt = SGGeod_snap( subject.GetNode(i), snap );
|
||||
result.AddNode(pt);
|
||||
}
|
||||
result.SetHole( subject.GetHole() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double tgContour::GetMinimumAngle( void ) const
|
||||
{
|
||||
unsigned int p1_index, p2_index, p3_index;
|
||||
double angle, min_angle = 2.0 * SGD_PI;
|
||||
unsigned int size = node_list.size();
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " tgContour::GetMinimumAngle() : contour size is " << size );
|
||||
|
||||
for ( unsigned int i = 0; i < size; i++ ) {
|
||||
if ( i == 0) {
|
||||
p1_index = size -1;
|
||||
} else {
|
||||
p1_index = i - 1;
|
||||
}
|
||||
|
||||
p2_index = i;
|
||||
|
||||
if ( i == size ) {
|
||||
p3_index = 0;
|
||||
} else {
|
||||
p3_index = i + 1;
|
||||
}
|
||||
|
||||
angle = SGGeod_CalculateTheta( node_list[p1_index], node_list[p2_index], node_list[p3_index] );
|
||||
if ( angle < min_angle ) {
|
||||
min_angle = angle;
|
||||
}
|
||||
}
|
||||
|
||||
return min_angle;
|
||||
}
|
||||
|
||||
double tgContour::GetArea( void ) const
|
||||
{
|
||||
double area = 0.0;
|
||||
SGVec2d a, b;
|
||||
unsigned int i, j;
|
||||
|
||||
if ( node_list.size() ) {
|
||||
j = node_list.size() - 1;
|
||||
for (i=0; i<node_list.size(); i++) {
|
||||
a = SGGeod_ToSGVec2d( node_list[i] );
|
||||
b = SGGeod_ToSGVec2d( node_list[j] );
|
||||
|
||||
area += (b.x() + a.x()) * (b.y() - a.y());
|
||||
j=i;
|
||||
}
|
||||
}
|
||||
|
||||
return fabs(area * 0.5);
|
||||
}
|
||||
|
||||
tgContour tgContour::RemoveCycles( const tgContour& subject )
|
||||
{
|
||||
tgContour result;
|
||||
bool found;
|
||||
int iters = 0;
|
||||
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); i++ )
|
||||
{
|
||||
result.AddNode( subject.GetNode(i) );
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove small cycles : original contour has " << result.GetSize() << " points" );
|
||||
|
||||
do
|
||||
{
|
||||
found = false;
|
||||
|
||||
// Step 1 - find a duplicate point
|
||||
for ( unsigned int i = 0; i < result.GetSize() && !found; i++ ) {
|
||||
// first check until the end of the vector
|
||||
for ( unsigned int j = i + 1; j < result.GetSize() && !found; j++ ) {
|
||||
if ( SGGeod_isEqual2D( result.GetNode(i), result.GetNode(j) ) ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a dupe: i = " << i << " j = " << j );
|
||||
|
||||
// We found a dupe - calculate the distance between them
|
||||
if ( i + 4 > j ) {
|
||||
// it's within target distance - remove the points in between, and start again
|
||||
if ( j-i == 1 ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << i );
|
||||
result.RemoveNodeAt( i );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from " << i << " to " << j-1 );
|
||||
result.RemoveNodeRange( i, j-1 );
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then check from beginning to the first point (wrap around)
|
||||
for ( unsigned int j = 0; j < i && !found; j++ ) {
|
||||
if ( (i != j) && ( SGGeod_isEqual2D( result.GetNode(i), result.GetNode(j) ) ) ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a dupe: i = " << i << " j = " << j );
|
||||
|
||||
// We found a dupe - calculate the distance between them
|
||||
if ( (result.GetSize() - i + j) < 4 ) {
|
||||
// it's within target distance - remove from the end point to the end of the vector
|
||||
if ( i == result.GetSize() - 1 ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << result.GetSize()-1 );
|
||||
result.RemoveNodeAt( result.GetSize()-1 );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from " << i << " to " << result.GetSize()-1 );
|
||||
result.RemoveNodeRange( i, result.GetSize()-1 );
|
||||
}
|
||||
|
||||
// then remove from the beginning of the vector to the beginning point
|
||||
if ( j == 1 ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing " << j-1 );
|
||||
result.RemoveNodeAt( 0 );
|
||||
} else if ( j > 1) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "detected a small cycle: i = " << i << " j = " << j << " Erasing from 0 " << " to " << j-1 );
|
||||
result.RemoveNodeRange( 0, j-1 );
|
||||
}
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iters++;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove small cycles : after " << iters << " iterations, contour has " << result.GetSize() << " points" );
|
||||
} while( found );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgContour tgContour::RemoveDups( const tgContour& subject )
|
||||
{
|
||||
tgContour result;
|
||||
|
||||
int iters = 0;
|
||||
bool found;
|
||||
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); i++ )
|
||||
{
|
||||
result.AddNode( subject.GetNode( i ) );
|
||||
}
|
||||
result.SetHole( subject.GetHole() );
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "remove contour dups : original contour has " << result.GetSize() << " points" );
|
||||
|
||||
do
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "remove_contour_dups: start new iteration" );
|
||||
found = false;
|
||||
|
||||
// Step 1 - find a neighboring duplicate points
|
||||
SGGeod cur, next;
|
||||
unsigned int cur_loc, next_loc;
|
||||
|
||||
for ( unsigned int i = 0; i < result.GetSize() && !found; i++ ) {
|
||||
if (i == result.GetSize() - 1 ) {
|
||||
cur_loc = i;
|
||||
cur = result.GetNode(i);
|
||||
|
||||
next_loc = 0;
|
||||
next = result.GetNode(0);
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " cur is last point: " << cur << " next is first point: " << next );
|
||||
} else {
|
||||
cur_loc = i;
|
||||
cur = result.GetNode(i);
|
||||
|
||||
next_loc = i+1;
|
||||
next = result.GetNode(i+1);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, " cur is: " << cur << " next is : " << next );
|
||||
}
|
||||
|
||||
if ( SGGeod_isEqual2D( cur, next ) ) {
|
||||
// keep the point with higher Z
|
||||
if ( cur.getElevationM() < next.getElevationM() ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_dups: erasing " << cur );
|
||||
result.RemoveNodeAt( cur_loc );
|
||||
// result.RemoveNodeAt( result.begin()+cur );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_dups: erasing " << next );
|
||||
result.RemoveNodeAt( next_loc );
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
iters++;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_dups : after " << iters << " iterations, contour has " << result.GetSize() << " points" );
|
||||
} while( found );
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
tgContour tgContour::SplitLongEdges( const tgContour& subject, double max_len )
|
||||
{
|
||||
SGGeod p0, p1;
|
||||
double dist;
|
||||
tgContour result;
|
||||
|
||||
for ( unsigned i = 0; i < subject.GetSize() - 1; i++ ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "point = " << i);
|
||||
|
||||
p0 = subject.GetNode( i );
|
||||
p1 = subject.GetNode( i + 1 );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " " << p0 << " - " << p1);
|
||||
|
||||
if ( fabs(p0.getLatitudeDeg()) < (90.0 - SG_EPSILON) ||
|
||||
fabs(p1.getLatitudeDeg()) < (90.0 - SG_EPSILON) )
|
||||
{
|
||||
dist = SGGeodesy::distanceM( p0, p1 );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "distance = " << dist);
|
||||
|
||||
if ( dist > max_len ) {
|
||||
unsigned int segments = (int)(dist / max_len) + 1;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "segments = " << segments);
|
||||
|
||||
double dx = (p1.getLongitudeDeg() - p0.getLongitudeDeg()) / segments;
|
||||
double dy = (p1.getLatitudeDeg() - p0.getLatitudeDeg()) / segments;
|
||||
|
||||
for ( unsigned int j = 0; j < segments; j++ ) {
|
||||
SGGeod tmp = SGGeod::fromDeg( p0.getLongitudeDeg() + dx * j, p0.getLatitudeDeg() + dy * j );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, tmp);
|
||||
result.AddNode( tmp );
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, p0);
|
||||
result.AddNode( p0 );
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, p0);
|
||||
result.AddNode( p0 );
|
||||
}
|
||||
|
||||
// end of segment is beginning of next segment
|
||||
}
|
||||
|
||||
p0 = subject.GetNode( subject.GetSize() - 1 );
|
||||
p1 = subject.GetNode( 0 );
|
||||
|
||||
dist = SGGeodesy::distanceM( p0, p1 );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "distance = " << dist);
|
||||
|
||||
if ( dist > max_len ) {
|
||||
unsigned int segments = (int)(dist / max_len) + 1;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "segments = " << segments);
|
||||
|
||||
double dx = (p1.getLongitudeDeg() - p0.getLongitudeDeg()) / segments;
|
||||
double dy = (p1.getLatitudeDeg() - p0.getLatitudeDeg()) / segments;
|
||||
|
||||
for ( unsigned int i = 0; i < segments; i++ ) {
|
||||
SGGeod tmp = SGGeod::fromDeg( p0.getLongitudeDeg() + dx * i, p0.getLatitudeDeg() + dy * i );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, tmp);
|
||||
result.AddNode( tmp );
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, p0);
|
||||
result.AddNode( p0 );
|
||||
}
|
||||
|
||||
// maintain original hole flag setting
|
||||
result.SetHole( subject.GetHole() );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "split_long_edges() complete");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgContour tgContour::RemoveSpikes( const tgContour& subject )
|
||||
{
|
||||
tgContour result;
|
||||
int iters = 0;
|
||||
double theta;
|
||||
bool found;
|
||||
SGGeod cur, prev, next;
|
||||
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); i++ )
|
||||
{
|
||||
result.AddNode( subject.GetNode( i ) );
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove contour spikes : original contour has " << result.GetSize() << " points" );
|
||||
|
||||
do
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes: start new iteration");
|
||||
found = false;
|
||||
|
||||
// Step 1 - find a duplicate point
|
||||
for ( unsigned int i = 0; i < result.GetSize() && !found; i++ ) {
|
||||
if (i == 0) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is first point: " << i << ": " << result.GetNode(i) );
|
||||
cur = result.GetNode( 0 );
|
||||
prev = result.GetNode( result.GetSize()-1 );
|
||||
next = result.GetNode( 1 );
|
||||
} else if ( i == result.GetSize()-1 ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is last point: " << i << ": " << result.GetNode(i) );
|
||||
cur = result.GetNode( i );
|
||||
prev = result.GetNode( i-1 );
|
||||
next = result.GetNode( 0 );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " cur is: " << i << ": " << result.GetNode(i) );
|
||||
cur = result.GetNode( i );
|
||||
prev = result.GetNode( i-1 );
|
||||
next = result.GetNode( i+1 );
|
||||
}
|
||||
|
||||
theta = SGMiscd::rad2deg( SGGeod_CalculateTheta(prev, cur, next) );
|
||||
|
||||
if ( abs(theta) < 0.1 ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes: (theta is " << theta << ") erasing " << i << " prev is " << prev << " cur is " << cur << " next is " << next );
|
||||
result.RemoveNodeAt( i );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
iters++;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_contour_spikes : after " << iters << " iterations, contour has " << result.GetSize() << " points" );
|
||||
} while( found );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ClipperLib::Polygon tgContour::ToClipper( const tgContour& subject )
|
||||
{
|
||||
ClipperLib::Polygon contour;
|
||||
|
||||
for ( unsigned int i=0; i<subject.GetSize(); i++)
|
||||
{
|
||||
SGGeod p = subject.GetNode( i );
|
||||
contour.push_back( SGGeod_ToClipper(p) );
|
||||
}
|
||||
|
||||
if ( subject.GetHole() )
|
||||
{
|
||||
// holes need to be orientation: false
|
||||
if ( Orientation( contour ) ) {
|
||||
//SG_LOG(SG_GENERAL, SG_INFO, "Building clipper contour - hole contour needs to be reversed" );
|
||||
ReversePolygon( contour );
|
||||
}
|
||||
} else {
|
||||
// boundaries need to be orientation: true
|
||||
if ( !Orientation( contour ) ) {
|
||||
//SG_LOG(SG_GENERAL, SG_INFO, "Building clipper contour - boundary contour needs to be reversed" );
|
||||
ReversePolygon( contour );
|
||||
}
|
||||
}
|
||||
|
||||
return contour;
|
||||
}
|
||||
|
||||
tgContour tgContour::FromClipper( const ClipperLib::Polygon& subject )
|
||||
{
|
||||
tgContour result;
|
||||
|
||||
for (unsigned int i = 0; i < subject.size(); i++)
|
||||
{
|
||||
ClipperLib::IntPoint ip = ClipperLib::IntPoint( subject[i].X, subject[i].Y );
|
||||
//SG_LOG(SG_GENERAL, SG_INFO, "Building tgContour : Add point (" << ip.X << "," << ip.Y << ") );
|
||||
result.AddNode( SGGeod_FromClipper( ip ) );
|
||||
}
|
||||
|
||||
if ( Orientation( subject ) ) {
|
||||
//SG_LOG(SG_GENERAL, SG_INFO, "Building tgContour as boundary " );
|
||||
result.SetHole(false);
|
||||
} else {
|
||||
//SG_LOG(SG_GENERAL, SG_INFO, "Building tgContour as hole " );
|
||||
result.SetHole(true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgRectangle tgContour::GetBoundingBox( void ) const
|
||||
{
|
||||
SGGeod min, max;
|
||||
|
||||
double minx = std::numeric_limits<double>::infinity();
|
||||
double miny = std::numeric_limits<double>::infinity();
|
||||
double maxx = -std::numeric_limits<double>::infinity();
|
||||
double maxy = -std::numeric_limits<double>::infinity();
|
||||
|
||||
for (unsigned int i = 0; i < node_list.size(); i++) {
|
||||
SGGeod pt = GetNode(i);
|
||||
if ( pt.getLongitudeDeg() < minx ) { minx = pt.getLongitudeDeg(); }
|
||||
if ( pt.getLongitudeDeg() > maxx ) { maxx = pt.getLongitudeDeg(); }
|
||||
if ( pt.getLatitudeDeg() < miny ) { miny = pt.getLatitudeDeg(); }
|
||||
if ( pt.getLatitudeDeg() > maxy ) { maxy = pt.getLatitudeDeg(); }
|
||||
}
|
||||
|
||||
min = SGGeod::fromDeg( minx, miny );
|
||||
max = SGGeod::fromDeg( maxx, maxy );
|
||||
|
||||
return tgRectangle( min, max );
|
||||
}
|
||||
|
||||
tgPolygon tgContour::Union( const tgContour& subject, tgPolygon& clip )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); ++i ) {
|
||||
all_nodes.add( subject.GetNode(i) );
|
||||
}
|
||||
|
||||
ClipperLib::Polygon clipper_subject = tgContour::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( clip );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygon(clipper_subject, ClipperLib::ptSubject);
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
|
||||
c.Execute(ClipperLib::ctUnion, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgContour::Diff( const tgContour& subject, tgPolygon& clip )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.GetSize(); ++i ) {
|
||||
all_nodes.add( subject.GetNode(i) );
|
||||
}
|
||||
|
||||
ClipperLib::Polygon clipper_subject = tgContour::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( clip );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygon(clipper_subject, ClipperLib::ptSubject);
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
|
||||
c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool FindIntermediateNode( const SGGeod& start, const SGGeod& end,
|
||||
const std::vector<SGGeod>& nodes, SGGeod& result,
|
||||
double bbEpsilon, double errEpsilon )
|
||||
{
|
||||
bool found_node = false;
|
||||
double m, m1, b, b1, y_err, x_err, y_err_min, x_err_min;
|
||||
|
||||
SGGeod p0 = start;
|
||||
SGGeod p1 = end;
|
||||
|
||||
double xdist = fabs(p0.getLongitudeDeg() - p1.getLongitudeDeg());
|
||||
double ydist = fabs(p0.getLatitudeDeg() - p1.getLatitudeDeg());
|
||||
|
||||
x_err_min = xdist + 1.0;
|
||||
y_err_min = ydist + 1.0;
|
||||
|
||||
if ( xdist > ydist ) {
|
||||
// sort these in a sensible order
|
||||
SGGeod p_min, p_max;
|
||||
if ( p0.getLongitudeDeg() < p1.getLongitudeDeg() ) {
|
||||
p_min = p0;
|
||||
p_max = p1;
|
||||
} else {
|
||||
p_min = p1;
|
||||
p_max = p0;
|
||||
}
|
||||
|
||||
m = (p_min.getLatitudeDeg() - p_max.getLatitudeDeg()) / (p_min.getLongitudeDeg() - p_max.getLongitudeDeg());
|
||||
b = p_max.getLatitudeDeg() - m * p_max.getLongitudeDeg();
|
||||
|
||||
for ( int i = 0; i < (int)nodes.size(); ++i ) {
|
||||
// cout << i << endl;
|
||||
SGGeod current = nodes[i];
|
||||
|
||||
if ( (current.getLongitudeDeg() > (p_min.getLongitudeDeg() + (bbEpsilon))) && (current.getLongitudeDeg() < (p_max.getLongitudeDeg() - (bbEpsilon))) ) {
|
||||
y_err = fabs(current.getLatitudeDeg() - (m * current.getLongitudeDeg() + b));
|
||||
|
||||
if ( y_err < errEpsilon ) {
|
||||
found_node = true;
|
||||
if ( y_err < y_err_min ) {
|
||||
result = current;
|
||||
y_err_min = y_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// sort these in a sensible order
|
||||
SGGeod p_min, p_max;
|
||||
if ( p0.getLatitudeDeg() < p1.getLatitudeDeg() ) {
|
||||
p_min = p0;
|
||||
p_max = p1;
|
||||
} else {
|
||||
p_min = p1;
|
||||
p_max = p0;
|
||||
}
|
||||
|
||||
m1 = (p_min.getLongitudeDeg() - p_max.getLongitudeDeg()) / (p_min.getLatitudeDeg() - p_max.getLatitudeDeg());
|
||||
b1 = p_max.getLongitudeDeg() - m1 * p_max.getLatitudeDeg();
|
||||
|
||||
for ( int i = 0; i < (int)nodes.size(); ++i ) {
|
||||
SGGeod current = nodes[i];
|
||||
|
||||
if ( (current.getLatitudeDeg() > (p_min.getLatitudeDeg() + (bbEpsilon))) && (current.getLatitudeDeg() < (p_max.getLatitudeDeg() - (bbEpsilon))) ) {
|
||||
|
||||
x_err = fabs(current.getLongitudeDeg() - (m1 * current.getLatitudeDeg() + b1));
|
||||
|
||||
if ( x_err < errEpsilon ) {
|
||||
found_node = true;
|
||||
if ( x_err < x_err_min ) {
|
||||
result = current;
|
||||
x_err_min = x_err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_node;
|
||||
}
|
||||
|
||||
static void AddIntermediateNodes( const SGGeod& p0, const SGGeod& p1, std::vector<SGGeod>& nodes, tgContour& result, double bbEpsilon, double errEpsilon )
|
||||
{
|
||||
SGGeod new_pt;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_BULK, " " << p0 << " <==> " << p1 );
|
||||
|
||||
bool found_extra = FindIntermediateNode( p0, p1, nodes, new_pt, bbEpsilon, errEpsilon );
|
||||
|
||||
if ( found_extra ) {
|
||||
AddIntermediateNodes( p0, new_pt, nodes, result, bbEpsilon, errEpsilon );
|
||||
|
||||
result.AddNode( new_pt );
|
||||
SG_LOG(SG_GENERAL, SG_BULK, " adding = " << new_pt);
|
||||
|
||||
AddIntermediateNodes( new_pt, p1, nodes, result, bbEpsilon, errEpsilon );
|
||||
}
|
||||
}
|
||||
|
||||
tgContour tgContour::AddColinearNodes( const tgContour& subject, UniqueSGGeodSet& nodes )
|
||||
{
|
||||
SGGeod p0, p1;
|
||||
tgContour result;
|
||||
std::vector<SGGeod>& tmp_nodes = nodes.get_list();
|
||||
|
||||
for ( unsigned int n = 0; n < subject.GetSize()-1; n++ ) {
|
||||
p0 = subject.GetNode( n );
|
||||
p1 = subject.GetNode( n+1 );
|
||||
|
||||
// add start of segment
|
||||
result.AddNode( p0 );
|
||||
|
||||
// add intermediate points
|
||||
AddIntermediateNodes( p0, p1, tmp_nodes, result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
}
|
||||
|
||||
p0 = subject.GetNode( subject.GetSize() - 1 );
|
||||
p1 = subject.GetNode( 0 );
|
||||
|
||||
// add start of segment
|
||||
result.AddNode( p0 );
|
||||
|
||||
// add intermediate points
|
||||
AddIntermediateNodes( p0, p1, tmp_nodes, result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// maintain original hole flag setting
|
||||
result.SetHole( subject.GetHole() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgContour tgContour::AddColinearNodes( const tgContour& subject, std::vector<SGGeod>& nodes )
|
||||
{
|
||||
SGGeod p0, p1;
|
||||
tgContour result;
|
||||
|
||||
for ( unsigned int n = 0; n < subject.GetSize()-1; n++ ) {
|
||||
p0 = subject.GetNode( n );
|
||||
p1 = subject.GetNode( n+1 );
|
||||
|
||||
// add start of segment
|
||||
result.AddNode( p0 );
|
||||
|
||||
// add intermediate points
|
||||
AddIntermediateNodes( p0, p1, nodes, result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
}
|
||||
|
||||
p0 = subject.GetNode( subject.GetSize() - 1 );
|
||||
p1 = subject.GetNode( 0 );
|
||||
|
||||
// add start of segment
|
||||
result.AddNode( p0 );
|
||||
|
||||
// add intermediate points
|
||||
AddIntermediateNodes( p0, p1, nodes, result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// maintain original hole flag setting
|
||||
result.SetHole( subject.GetHole() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// this is the opposite of FindColinearNodes - it takes a single SGGeode,
|
||||
// and tries to find the line segment the point is colinear with
|
||||
bool tgContour::FindColinearLine( const tgContour& subject, const SGGeod& node, SGGeod& start, SGGeod& end )
|
||||
{
|
||||
SGGeod p0, p1;
|
||||
SGGeod new_pt;
|
||||
std::vector<SGGeod> tmp_nodes;
|
||||
|
||||
tmp_nodes.push_back( node );
|
||||
for ( unsigned int n = 0; n < subject.GetSize()-1; n++ ) {
|
||||
p0 = subject.GetNode( n );
|
||||
p1 = subject.GetNode( n+1 );
|
||||
|
||||
// add intermediate points
|
||||
bool found_extra = FindIntermediateNode( p0, p1, tmp_nodes, new_pt, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
if ( found_extra ) {
|
||||
start = p0;
|
||||
end = p1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// check last segment
|
||||
p0 = subject.GetNode( subject.GetSize() - 1 );
|
||||
p1 = subject.GetNode( 0 );
|
||||
|
||||
// add intermediate points
|
||||
bool found_extra = FindIntermediateNode( p0, p1, tmp_nodes, new_pt, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
if ( found_extra ) {
|
||||
start = p0;
|
||||
end = p1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tgContour tgContour::Expand( const tgContour& subject, double offset )
|
||||
{
|
||||
tgPolygon poly;
|
||||
tgContour result;
|
||||
|
||||
poly.AddContour( subject );
|
||||
ClipperLib::Polygons clipper_src, clipper_dst;
|
||||
|
||||
clipper_src = tgPolygon::ToClipper( poly );
|
||||
|
||||
// convert delta from meters to clipper units
|
||||
OffsetPolygons( clipper_src, clipper_dst, Dist_ToClipper(offset) );
|
||||
|
||||
poly = tgPolygon::FromClipper( clipper_dst );
|
||||
|
||||
if ( poly.Contours() == 1 ) {
|
||||
result = poly.GetContour( 0 );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Expanding contour resulted in more than 1 contour ! ");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgpolygon_list tgContour::ExpandToPolygons( const tgContour& subject, double width )
|
||||
{
|
||||
int turn_dir;
|
||||
|
||||
SGGeod cur_inner;
|
||||
SGGeod cur_outer;
|
||||
SGGeod prev_inner;
|
||||
SGGeod prev_outer;
|
||||
SGGeod calc_inner;
|
||||
SGGeod calc_outer;
|
||||
|
||||
double last_end_v = 0.0f;
|
||||
|
||||
tgContour expanded;
|
||||
tgPolygon segment;
|
||||
tgAccumulator accum;
|
||||
tgpolygon_list result;
|
||||
|
||||
// generate poly and texparam lists for each line segment
|
||||
for (unsigned int i = 0; i < subject.GetSize(); i++)
|
||||
{
|
||||
last_end_v = 0.0f;
|
||||
turn_dir = 0;
|
||||
|
||||
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "makePolygonsTP: calculating offsets for segment " << i);
|
||||
|
||||
// for each point on the PointsList, generate a quad from
|
||||
// start to next, offset by 1/2 width from the edge
|
||||
if (i == 0)
|
||||
{
|
||||
// first point on the list - offset heading is 90deg
|
||||
cur_outer = OffsetPointFirst( subject.GetNode(i), subject.GetNode(i+1), -width/2.0f );
|
||||
cur_inner = OffsetPointFirst( subject.GetNode(i), subject.GetNode(i+1), width/2.0f );
|
||||
}
|
||||
else if (i == subject.GetSize()-1)
|
||||
{
|
||||
// last point on the list - offset heading is 90deg
|
||||
cur_outer = OffsetPointLast( subject.GetNode(i-1), subject.GetNode(i), -width/2.0f );
|
||||
cur_inner = OffsetPointLast( subject.GetNode(i-1), subject.GetNode(i), width/2.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
// middle section
|
||||
cur_outer = OffsetPointMiddle( subject.GetNode(i-1), subject.GetNode(i), subject.GetNode(i+1), -width/2.0f, turn_dir );
|
||||
cur_inner = OffsetPointMiddle( subject.GetNode(i-1), subject.GetNode(i), subject.GetNode(i+1), width/2.0f, turn_dir );
|
||||
}
|
||||
|
||||
if ( i > 0 )
|
||||
{
|
||||
SGGeod prev_mp = midpoint( prev_outer, prev_inner );
|
||||
SGGeod cur_mp = midpoint( cur_outer, cur_inner );
|
||||
SGGeod intersect;
|
||||
double heading;
|
||||
double dist;
|
||||
double az2;
|
||||
|
||||
SGGeodesy::inverse( prev_mp, cur_mp, heading, az2, dist );
|
||||
|
||||
expanded.Erase();
|
||||
segment.Erase();
|
||||
|
||||
expanded.AddNode( prev_inner );
|
||||
expanded.AddNode( prev_outer );
|
||||
|
||||
// we need to extend one of the points so we're sure we don't create adjacent edges
|
||||
if (turn_dir == 0)
|
||||
{
|
||||
// turned right - offset outer
|
||||
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
|
||||
{
|
||||
// yes - make a triangle with inner edge = 0
|
||||
expanded.AddNode( cur_outer );
|
||||
cur_inner = prev_inner;
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded.AddNode( cur_outer );
|
||||
expanded.AddNode( cur_inner );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// turned left - offset inner
|
||||
if ( intersection( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
|
||||
{
|
||||
// yes - make a triangle with outer edge = 0
|
||||
expanded.AddNode( cur_inner );
|
||||
cur_outer = prev_outer;
|
||||
}
|
||||
else
|
||||
{
|
||||
expanded.AddNode( cur_outer );
|
||||
expanded.AddNode( cur_inner );
|
||||
}
|
||||
}
|
||||
|
||||
expanded.SetHole(false);
|
||||
segment.AddContour(expanded);
|
||||
segment.SetTexParams( prev_inner, width, 20.0f, heading );
|
||||
segment.SetTexLimits( 0, last_end_v, 1, 1 );
|
||||
segment.SetTexMethod( TG_TEX_BY_TPS_CLIPU, -1.0, 0.0, 1.0, 0.0 );
|
||||
result.push_back( segment );
|
||||
|
||||
last_end_v = 1.0f - (fmod( (double)(dist - last_end_v), (double)1.0f ));
|
||||
}
|
||||
|
||||
prev_outer = cur_outer;
|
||||
prev_inner = cur_inner;
|
||||
}
|
||||
|
||||
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tgContour::SaveToGzFile( gzFile& fp ) const
|
||||
{
|
||||
// Save the nodelist
|
||||
sgWriteUInt( fp, node_list.size() );
|
||||
for (unsigned int i = 0; i < node_list.size(); i++) {
|
||||
sgWriteGeod( fp, node_list[i] );
|
||||
}
|
||||
|
||||
// and the hole flag
|
||||
sgWriteInt( fp, (int)hole );
|
||||
}
|
||||
|
||||
void tgContour::LoadFromGzFile( gzFile& fp )
|
||||
{
|
||||
unsigned int count;
|
||||
SGGeod node;
|
||||
|
||||
// Start Clean
|
||||
Erase();
|
||||
|
||||
// Load the nodelist
|
||||
sgReadUInt( fp, &count );
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
sgReadGeod( fp, node );
|
||||
node_list.push_back( node );
|
||||
}
|
||||
|
||||
sgReadInt( fp, (int *)&hole );
|
||||
}
|
||||
|
||||
std::ostream& operator<< ( std::ostream& output, const tgContour& subject )
|
||||
{
|
||||
// Save the data
|
||||
output << "NumNodes: " << subject.node_list.size() << "\n";
|
||||
|
||||
for( unsigned int n=0; n<subject.node_list.size(); n++) {
|
||||
output << subject.node_list[n] << "\n";
|
||||
}
|
||||
|
||||
output << "Hole: " << subject.hole << "\n";
|
||||
|
||||
return output;
|
||||
}
|
112
src/Lib/terragear/tg_contour.hxx
Normal file
112
src/Lib/terragear/tg_contour.hxx
Normal file
|
@ -0,0 +1,112 @@
|
|||
#ifndef _TGCONTOUR_HXX
|
||||
#define _TGCONTOUR_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/sg_types.hxx>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
#include "tg_unique_geod.hxx"
|
||||
#include "tg_rectangle.hxx"
|
||||
#include "clipper.hpp"
|
||||
|
||||
/* forward declarations */
|
||||
class tgPolygon;
|
||||
typedef std::vector <tgPolygon> tgpolygon_list;
|
||||
|
||||
class tgContour
|
||||
{
|
||||
public:
|
||||
tgContour() {
|
||||
hole = false;
|
||||
}
|
||||
|
||||
void Erase() {
|
||||
node_list.clear();
|
||||
}
|
||||
|
||||
void SetHole( bool h ) {
|
||||
hole = h;
|
||||
}
|
||||
bool GetHole( void ) const {
|
||||
return hole;
|
||||
}
|
||||
|
||||
unsigned int GetSize( void ) const {
|
||||
return node_list.size();
|
||||
}
|
||||
|
||||
void Resize( int size ) {
|
||||
node_list.resize( size );
|
||||
}
|
||||
|
||||
void AddNode( SGGeod n ) {
|
||||
node_list.push_back( n );
|
||||
}
|
||||
void SetNode( unsigned int i, SGGeod n ) {
|
||||
node_list[i] = n;
|
||||
}
|
||||
SGGeod GetNode( unsigned int i ) const {
|
||||
return node_list[i];
|
||||
}
|
||||
SGGeod const& operator[]( int index ) const {
|
||||
return node_list[index];
|
||||
}
|
||||
|
||||
void RemoveNodeAt( unsigned int idx ) {
|
||||
if ( idx < node_list.size() ) {
|
||||
node_list.erase( node_list.begin() + idx );
|
||||
}
|
||||
}
|
||||
void RemoveNodeRange( unsigned int from, unsigned int to ) {
|
||||
if ( ( from < to ) && ( to < node_list.size() ) ) {
|
||||
node_list.erase( node_list.begin()+from,node_list.begin()+to );
|
||||
}
|
||||
}
|
||||
|
||||
tgRectangle GetBoundingBox( void ) const;
|
||||
|
||||
double GetMinimumAngle( void ) const;
|
||||
double GetArea( void ) const;
|
||||
|
||||
static tgContour Snap( const tgContour& subject, double snap );
|
||||
static tgContour RemoveDups( const tgContour& subject );
|
||||
static tgContour RemoveCycles( const tgContour& subject );
|
||||
static tgContour SplitLongEdges( const tgContour& subject, double dist );
|
||||
static tgContour RemoveSpikes( const tgContour& subject );
|
||||
|
||||
static tgPolygon Union( const tgContour& subject, tgPolygon& clip );
|
||||
static tgPolygon Diff( const tgContour& subject, tgPolygon& clip );
|
||||
|
||||
static tgContour AddColinearNodes( const tgContour& subject, UniqueSGGeodSet& nodes );
|
||||
static tgContour AddColinearNodes( const tgContour& subject, std::vector<SGGeod>& nodes );
|
||||
static bool FindColinearLine( const tgContour& subject, const SGGeod& node, SGGeod& start, SGGeod& end );
|
||||
|
||||
// conversions
|
||||
static ClipperLib::Polygon ToClipper( const tgContour& subject );
|
||||
static tgContour FromClipper( const ClipperLib::Polygon& subject );
|
||||
|
||||
static tgContour Expand( const tgContour& subject, double offset );
|
||||
static tgpolygon_list ExpandToPolygons( const tgContour& subject, double width );
|
||||
|
||||
static void ToShapefile( const tgContour& subject, const std::string& datasource, const std::string& layer, const std::string& feature );
|
||||
|
||||
void SaveToGzFile( gzFile& fp ) const;
|
||||
void LoadFromGzFile( gzFile& fp );
|
||||
|
||||
// Friend for output
|
||||
friend std::ostream& operator<< ( std::ostream&, const tgContour& );
|
||||
|
||||
private:
|
||||
std::vector<SGGeod> node_list;
|
||||
bool hole;
|
||||
};
|
||||
|
||||
typedef std::vector <tgContour> tgcontour_list;
|
||||
typedef tgcontour_list::iterator tgcontour_list_iterator;
|
||||
typedef tgcontour_list::const_iterator const_tgcontour_list_iterator;
|
||||
|
||||
#endif // _TGCONTOUR_HXX
|
95
src/Lib/terragear/tg_light.hxx
Normal file
95
src/Lib/terragear/tg_light.hxx
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef _TG_LIGHT_HXX
|
||||
#define _TG_LIGHT_HXX
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
class tgLight
|
||||
{
|
||||
public:
|
||||
SGGeod pos;
|
||||
SGVec3f norm;
|
||||
};
|
||||
|
||||
typedef std::vector <tgLight> tglight_list;
|
||||
typedef tglight_list::iterator tglight_list_iterator;
|
||||
typedef tglight_list::const_iterator const_tglight_list_iterator;
|
||||
|
||||
class tgLightContour
|
||||
{
|
||||
public:
|
||||
unsigned int ContourSize( void ) const {
|
||||
return lights.size();
|
||||
}
|
||||
|
||||
void AddLight( SGGeod p, SGVec3f n ) {
|
||||
tgLight light;
|
||||
light.pos = p;
|
||||
light.norm = n;
|
||||
lights.push_back(light);
|
||||
}
|
||||
|
||||
void SetElevation( unsigned int i, double elev ) {
|
||||
lights[i].pos.setElevationM( elev );
|
||||
}
|
||||
|
||||
SGGeod GetNode( unsigned int i ) const {
|
||||
return lights[i].pos;
|
||||
}
|
||||
|
||||
SGGeod GetPosition( unsigned int i ) const {
|
||||
return lights[i].pos;
|
||||
}
|
||||
|
||||
SGVec3f GetNormal( unsigned int i ) const {
|
||||
return lights[i].norm;
|
||||
}
|
||||
|
||||
std::string GetFlag( void ) const {
|
||||
return flag;
|
||||
}
|
||||
void SetFlag( const std::string f ) {
|
||||
flag = f;
|
||||
}
|
||||
|
||||
std::string GetType( void ) const {
|
||||
return type;
|
||||
}
|
||||
void SetType( const std::string t ) {
|
||||
type = t;
|
||||
}
|
||||
|
||||
std::vector<SGGeod> GetPositionList( void ) {
|
||||
std::vector<SGGeod> positions;
|
||||
|
||||
for (unsigned int i=0; i<lights.size(); i++) {
|
||||
positions.push_back( lights[i].pos );
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
std::vector<SGVec3f> GetNormalList( void ) {
|
||||
std::vector<SGVec3f> normals;
|
||||
|
||||
for (unsigned int i=0; i<lights.size(); i++) {
|
||||
normals.push_back( lights[i].norm );
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
// Friend for output
|
||||
friend std::ostream& operator<< ( std::ostream&, const tgLightContour& );
|
||||
|
||||
std::string type;
|
||||
std::string flag;
|
||||
tglight_list lights;
|
||||
};
|
||||
|
||||
typedef std::vector <tgLightContour> tglightcontour_list;
|
||||
typedef tglightcontour_list::iterator tglightcontour_list_iterator;
|
||||
typedef tglightcontour_list::const_iterator const_tglightcontour_list_iterator;
|
||||
|
||||
#endif // _TG_LIGHT_HXX
|
269
src/Lib/terragear/tg_misc.cxx
Normal file
269
src/Lib/terragear/tg_misc.cxx
Normal file
|
@ -0,0 +1,269 @@
|
|||
#include <limits.h>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/intersections.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
#include "tg_misc.hxx"
|
||||
|
||||
const double isEqual2D_Epsilon = 0.000001;
|
||||
|
||||
#define CLIPPER_FIXEDPT (10000000000000000)
|
||||
#define CLIPPER_FIXED1M ( 90090)
|
||||
|
||||
SGGeod SGGeod_snap( const SGGeod& in, double grid )
|
||||
{
|
||||
return SGGeod::fromDegM( grid * SGMisc<double>::round( in.getLongitudeDeg()/grid ),
|
||||
grid * SGMisc<double>::round( in.getLatitudeDeg() /grid ),
|
||||
grid * SGMisc<double>::round( in.getElevationM() /grid ) );
|
||||
}
|
||||
|
||||
bool SGGeod_isEqual2D( const SGGeod& g0, const SGGeod& g1 )
|
||||
{
|
||||
return ( (fabs( g0.getLongitudeDeg() - g1.getLongitudeDeg() ) < isEqual2D_Epsilon) &&
|
||||
(fabs( g0.getLatitudeDeg() - g1.getLatitudeDeg() ) < isEqual2D_Epsilon ) );
|
||||
}
|
||||
|
||||
SGVec2d SGGeod_ToSGVec2d( const SGGeod& p )
|
||||
{
|
||||
return SGVec2d( p.getLongitudeDeg(), p.getLatitudeDeg() );
|
||||
}
|
||||
|
||||
// Calculate theta of angle (a, b, c)
|
||||
double SGGeod_CalculateTheta( const SGGeod& p0, const SGGeod& p1, const SGGeod& p2 )
|
||||
{
|
||||
SGVec2d v0 = SGGeod_ToSGVec2d( p0 );
|
||||
SGVec2d v1 = SGGeod_ToSGVec2d( p1 );
|
||||
SGVec2d v2 = SGGeod_ToSGVec2d( p2 );
|
||||
|
||||
return SGVec2d_CalculateTheta( v0, v1, v2 );
|
||||
}
|
||||
|
||||
// Calculate theta of angle of v0, v1, and v2 - vectors represent cartestian positions
|
||||
double SGVec2d_CalculateTheta( const SGVec2d& v0, const SGVec2d& v1, const SGVec2d& v2 )
|
||||
{
|
||||
SGVec2d u, v;
|
||||
double udist, vdist, uv_dot;
|
||||
|
||||
// u . v = ||u|| * ||v|| * cos(theta)
|
||||
|
||||
u = v1 - v0;
|
||||
udist = dist(v1, v2);
|
||||
|
||||
v = v1 - v2;
|
||||
vdist = dist(v1, v2);
|
||||
|
||||
uv_dot = dot(u, v);
|
||||
|
||||
return acos(uv_dot / (udist * vdist) );
|
||||
}
|
||||
|
||||
// calculate theta from two directions
|
||||
double CalculateTheta( const SGVec3d& dirCur, const SGVec3d& dirNext )
|
||||
{
|
||||
double dp = dot( dirCur, dirNext );
|
||||
|
||||
return acos( dp );
|
||||
}
|
||||
|
||||
ClipperLib::IntPoint SGGeod_ToClipper( const SGGeod& p )
|
||||
{
|
||||
ClipperLib::long64 x, y;
|
||||
|
||||
x = (ClipperLib::long64)( p.getLongitudeDeg() * CLIPPER_FIXEDPT );
|
||||
y = (ClipperLib::long64)( p.getLatitudeDeg() * CLIPPER_FIXEDPT );
|
||||
|
||||
return ClipperLib::IntPoint( x, y );
|
||||
}
|
||||
|
||||
SGGeod SGGeod_FromClipper( const ClipperLib::IntPoint& p )
|
||||
{
|
||||
double lon, lat;
|
||||
|
||||
lon = (double)( ((double)p.X) / (double)CLIPPER_FIXEDPT );
|
||||
lat = (double)( ((double)p.Y) / (double)CLIPPER_FIXEDPT );
|
||||
|
||||
return SGGeod::fromDeg( lon, lat );
|
||||
}
|
||||
|
||||
double Dist_ToClipper( double dist )
|
||||
{
|
||||
return ( dist * ( CLIPPER_FIXEDPT / CLIPPER_FIXED1M ) );
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define LONG_LONG_MAX LLONG_MAX
|
||||
# define LONG_LONG_MIN LLONG_MIN
|
||||
#endif
|
||||
|
||||
tgRectangle BoundingBox_FromClipper( const ClipperLib::Polygons& subject )
|
||||
{
|
||||
ClipperLib::IntPoint min_pt, max_pt;
|
||||
SGGeod min, max;
|
||||
|
||||
min_pt.X = min_pt.Y = LONG_LONG_MAX;
|
||||
max_pt.X = max_pt.Y = LONG_LONG_MIN;
|
||||
|
||||
// for each polygon, we need to check the orientation, to set the hole flag...
|
||||
for (unsigned int i=0; i<subject.size(); i++)
|
||||
{
|
||||
for (unsigned int j = 0; j < subject[i].size(); j++)
|
||||
{
|
||||
if ( subject[i][j].X < min_pt.X ) {
|
||||
min_pt.X = subject[i][j].X;
|
||||
}
|
||||
if ( subject[i][j].Y < min_pt.Y ) {
|
||||
min_pt.Y = subject[i][j].Y;
|
||||
}
|
||||
|
||||
if ( subject[i][j].X > max_pt.X ) {
|
||||
max_pt.X = subject[i][j].X;
|
||||
}
|
||||
if ( subject[i][j].Y > max_pt.Y ) {
|
||||
max_pt.Y = subject[i][j].Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
min = SGGeod_FromClipper( min_pt );
|
||||
max = SGGeod_FromClipper( max_pt );
|
||||
|
||||
return tgRectangle( min, max );
|
||||
}
|
||||
|
||||
SGGeod OffsetPointMiddle( const SGGeod& gPrev, const SGGeod& gCur, const SGGeod& gNext, double offset_by, int& turn_dir )
|
||||
{
|
||||
double courseCur, courseNext, courseAvg, theta;
|
||||
SGVec3d dirCur, dirNext, dirAvg, cp;
|
||||
double courseOffset, distOffset;
|
||||
SGGeod pt;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Find average angle for contour: prev (" << gPrev << "), "
|
||||
"cur (" << gCur << "), "
|
||||
"next (" << gNext << ")" );
|
||||
|
||||
// first, find if the line turns left or right ar src
|
||||
// for this, take the cross product of the vectors from prev to src, and src to next.
|
||||
// if the cross product is negetive, we've turned to the left
|
||||
// if the cross product is positive, we've turned to the right
|
||||
courseCur = SGGeodesy::courseDeg( gCur, gPrev );
|
||||
dirCur = SGVec3d( sin( courseCur*SGD_DEGREES_TO_RADIANS ), cos( courseCur*SGD_DEGREES_TO_RADIANS ), 0.0f );
|
||||
|
||||
courseNext = SGGeodesy::courseDeg( gCur, gNext );
|
||||
dirNext = SGVec3d( sin( courseNext*SGD_DEGREES_TO_RADIANS ), cos( courseNext*SGD_DEGREES_TO_RADIANS ), 0.0f );
|
||||
|
||||
// Now find the average
|
||||
dirAvg = normalize( dirCur + dirNext );
|
||||
courseAvg = SGMiscd::rad2deg( atan( dirAvg.x()/dirAvg.y() ) );
|
||||
if (courseAvg < 0) {
|
||||
courseAvg += 180.0f;
|
||||
}
|
||||
|
||||
// check the turn direction
|
||||
cp = cross( dirCur, dirNext );
|
||||
theta = SGMiscd::rad2deg(CalculateTheta( dirCur, dirNext ) );
|
||||
|
||||
if ( (abs(theta - 180.0) < 0.1) || (abs(theta) < 0.1) || (isnan(theta)) ) {
|
||||
// straight line blows up math - offset 90 degree and dist is as given
|
||||
courseOffset = SGMiscd::normalizePeriodic(0, 360, courseNext-90.0);
|
||||
distOffset = offset_by;
|
||||
} else {
|
||||
// calculate correct distance for the offset point
|
||||
if (cp.z() < 0.0f) {
|
||||
courseOffset = SGMiscd::normalizePeriodic(0, 360, courseAvg+180);
|
||||
turn_dir = 0;
|
||||
} else {
|
||||
courseOffset = SGMiscd::normalizePeriodic(0, 360, courseAvg);
|
||||
turn_dir = 1;
|
||||
}
|
||||
distOffset = (offset_by)/sin(SGMiscd::deg2rad(courseNext-courseOffset));
|
||||
}
|
||||
|
||||
// calculate the point from cur
|
||||
pt = SGGeodesy::direct(gCur, courseOffset, distOffset);
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "\theading is " << courseOffset << " distance is " << distOffset << " point is (" << pt.getLatitudeDeg() << "," << pt.getLongitudeDeg() << ")" );
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
SGGeod OffsetPointMiddle( const SGGeod& gPrev, const SGGeod& gCur, const SGGeod& gNext, double offset_by )
|
||||
{
|
||||
int unused;
|
||||
return OffsetPointMiddle( gPrev, gCur, gNext, offset_by, unused );
|
||||
}
|
||||
|
||||
SGGeod OffsetPointFirst( const SGGeod& cur, const SGGeod& next, double offset_by )
|
||||
{
|
||||
double courseOffset;
|
||||
SGGeod pt;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Find OffsetPoint at Start : cur (" << cur << "), "
|
||||
"next (" << next << ")" );
|
||||
|
||||
// find the offset angle
|
||||
courseOffset = SGGeodesy::courseDeg( cur, next ) - 90;
|
||||
courseOffset = SGMiscd::normalizePeriodic(0, 360, courseOffset);
|
||||
|
||||
// calculate the point from cur
|
||||
pt = SGGeodesy::direct( cur, courseOffset, offset_by );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "\theading is " << courseOffset << " distance is " << offset_by << " point is (" << pt.getLatitudeDeg() << "," << pt.getLongitudeDeg() << ")" );
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
SGGeod OffsetPointLast( const SGGeod& prev, const SGGeod& cur, double offset_by )
|
||||
{
|
||||
double courseOffset;
|
||||
SGGeod pt;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Find OffsetPoint at End : prev (" << prev << "), "
|
||||
"cur (" << cur << ")" );
|
||||
|
||||
// find the offset angle
|
||||
courseOffset = SGGeodesy::courseDeg( prev, cur ) - 90;
|
||||
courseOffset = SGMiscd::normalizePeriodic(0, 360, courseOffset);
|
||||
|
||||
// calculate the point from cur
|
||||
pt = SGGeodesy::direct( cur, courseOffset, offset_by );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "\theading is " << courseOffset << " distance is " << offset_by << " point is (" << pt.getLatitudeDeg() << "," << pt.getLongitudeDeg() << ")" );
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
SGGeod midpoint( const SGGeod& p0, const SGGeod& p1 )
|
||||
{
|
||||
return SGGeod::fromDegM( (p0.getLongitudeDeg() + p1.getLongitudeDeg()) / 2,
|
||||
(p0.getLatitudeDeg() + p1.getLatitudeDeg()) / 2,
|
||||
(p0.getElevationM() + p1.getElevationM()) / 2 );
|
||||
}
|
||||
|
||||
bool intersection(const SGGeod &p0, const SGGeod &p1, const SGGeod& p2, const SGGeod& p3, SGGeod& intersection)
|
||||
{
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
typedef CGAL::Segment_2<Kernel> Segment_2;
|
||||
|
||||
Point_2 a1( p0.getLongitudeDeg(), p0.getLatitudeDeg() );
|
||||
Point_2 b1( p1.getLongitudeDeg(), p1.getLatitudeDeg() );
|
||||
Point_2 a2( p2.getLongitudeDeg(), p2.getLatitudeDeg() );
|
||||
Point_2 b2( p3.getLongitudeDeg(), p3.getLatitudeDeg() );
|
||||
|
||||
Segment_2 seg1( a1, b1 );
|
||||
Segment_2 seg2( a2, b2 );
|
||||
|
||||
CGAL::Object result = CGAL::intersection(seg1, seg2);
|
||||
if (const CGAL::Point_2<Kernel> *ipoint = CGAL::object_cast<CGAL::Point_2<Kernel> >(&result)) {
|
||||
// handle the point intersection case with *ipoint.
|
||||
return true;
|
||||
} else {
|
||||
if (const CGAL::Segment_2<Kernel> *iseg = CGAL::object_cast<CGAL::Segment_2<Kernel> >(&result)) {
|
||||
// handle the segment intersection case with *iseg.
|
||||
return false;
|
||||
} else {
|
||||
// handle the no intersection case.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
33
src/Lib/terragear/tg_misc.hxx
Normal file
33
src/Lib/terragear/tg_misc.hxx
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include "clipper.hpp"
|
||||
#include "tg_rectangle.hxx"
|
||||
|
||||
// SGGeod Cleanup
|
||||
SGGeod SGGeod_snap( const SGGeod& in, double grid );
|
||||
|
||||
// SGGeod Conversion
|
||||
SGVec2d SGGeod_ToSGVec2d( const SGGeod& p );
|
||||
ClipperLib::IntPoint SGGeod_ToClipper( const SGGeod& p );
|
||||
SGGeod SGGeod_FromClipper( const ClipperLib::IntPoint& p );
|
||||
|
||||
// SGGeod Equivelence test
|
||||
bool SGGeod_isEqual2D( const SGGeod& g0, const SGGeod& g1 );
|
||||
|
||||
// SGGeod Angle calculation
|
||||
double SGGeod_CalculateTheta( const SGGeod& p0, const SGGeod& p1, const SGGeod& p2 );
|
||||
|
||||
// SGVec2d Angle calculation
|
||||
double SGVec2d_CalculateTheta( const SGVec2d& v0, const SGVec2d& v1, const SGVec2d& v2);
|
||||
|
||||
// Angle calculation from 2 directions
|
||||
double CalculateTheta( const SGVec3d& dirCur, const SGVec3d& dirNext );
|
||||
|
||||
// Clipper Conversion
|
||||
double Dist_ToClipper( double dist );
|
||||
|
||||
// should be in rectangle
|
||||
tgRectangle BoundingBox_FromClipper( const ClipperLib::Polygons& subject );
|
||||
|
||||
bool intersection(const SGGeod &p0, const SGGeod &p1, const SGGeod& p2, const SGGeod& p3, SGGeod& intersection);
|
||||
|
|
@ -39,7 +39,7 @@ typedef CGAL::Kd_tree<Traits> Tree;
|
|||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/io/lowlevel.hxx>
|
||||
|
||||
#include <Polygon/tg_unique_tgnode.hxx>
|
||||
#include "tg_unique_tgnode.hxx"
|
||||
|
||||
#define FG_PROXIMITY_EPSILON 0.000001
|
||||
#define FG_COURSE_EPSILON 0.0001
|
519
src/Lib/terragear/tg_polygon.cxx
Normal file
519
src/Lib/terragear/tg_polygon.cxx
Normal file
|
@ -0,0 +1,519 @@
|
|||
// polygon.cxx -- polygon (with holes) management class
|
||||
//
|
||||
// Written by Curtis Olson, started March 1999.
|
||||
//
|
||||
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGGuard.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/io/lowlevel.hxx>
|
||||
#include <simgear/misc/texcoord.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
|
||||
#include "tg_misc.hxx"
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
// tgPolygon static functions
|
||||
unsigned int tgPolygon::TotalNodes( void ) const
|
||||
{
|
||||
unsigned int total_nodes = 0;
|
||||
|
||||
for (unsigned int c = 0; c < contours.size(); c++) {
|
||||
total_nodes += contours[c].GetSize();
|
||||
}
|
||||
|
||||
return total_nodes;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Expand( const tgPolygon& subject, double offset )
|
||||
{
|
||||
ClipperLib::Polygons clipper_src, clipper_dst;
|
||||
clipper_src = tgPolygon::ToClipper( subject );
|
||||
tgPolygon result;
|
||||
|
||||
// convert delta from meters to clipper units
|
||||
OffsetPolygons( clipper_src, clipper_dst, Dist_ToClipper(offset) );
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_dst );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Expand( const SGGeod& subject, double offset )
|
||||
{
|
||||
tgPolygon result;
|
||||
tgContour contour;
|
||||
SGGeod pt;
|
||||
|
||||
pt = SGGeodesy::direct( subject, 90, offset/2.0 );
|
||||
double dlon = pt.getLongitudeDeg() - subject.getLongitudeDeg();
|
||||
|
||||
pt = SGGeodesy::direct( subject, 0, offset/2.0 );
|
||||
double dlat = pt.getLatitudeDeg() - subject.getLatitudeDeg();
|
||||
|
||||
contour.AddNode( SGGeod::fromDeg( subject.getLongitudeDeg() - dlon, subject.getLatitudeDeg() - dlat ) );
|
||||
contour.AddNode( SGGeod::fromDeg( subject.getLongitudeDeg() + dlon, subject.getLatitudeDeg() - dlat ) );
|
||||
contour.AddNode( SGGeod::fromDeg( subject.getLongitudeDeg() + dlon, subject.getLatitudeDeg() + dlat ) );
|
||||
contour.AddNode( SGGeod::fromDeg( subject.getLongitudeDeg() - dlon, subject.getLatitudeDeg() + dlat ) );
|
||||
contour.SetHole(false);
|
||||
|
||||
result.AddContour( contour );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgRectangle tgPolygon::GetBoundingBox( void ) const
|
||||
{
|
||||
SGGeod min, max;
|
||||
|
||||
double minx = std::numeric_limits<double>::infinity();
|
||||
double miny = std::numeric_limits<double>::infinity();
|
||||
double maxx = -std::numeric_limits<double>::infinity();
|
||||
double maxy = -std::numeric_limits<double>::infinity();
|
||||
|
||||
for ( unsigned int i = 0; i < Contours(); i++ ) {
|
||||
for (unsigned int j = 0; j < ContourSize(i); j++) {
|
||||
SGGeod pt = GetNode(i,j);
|
||||
if ( pt.getLongitudeDeg() < minx ) { minx = pt.getLongitudeDeg(); }
|
||||
if ( pt.getLongitudeDeg() > maxx ) { maxx = pt.getLongitudeDeg(); }
|
||||
if ( pt.getLatitudeDeg() < miny ) { miny = pt.getLatitudeDeg(); }
|
||||
if ( pt.getLatitudeDeg() > maxy ) { maxy = pt.getLatitudeDeg(); }
|
||||
}
|
||||
}
|
||||
|
||||
min = SGGeod::fromDeg( minx, miny );
|
||||
max = SGGeod::fromDeg( maxx, maxy );
|
||||
|
||||
return tgRectangle( min, max );
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::AddColinearNodes( const tgPolygon& subject, std::vector<SGGeod>& nodes )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
result.AddContour( tgContour::AddColinearNodes( subject.GetContour(c), nodes ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::AddColinearNodes( const tgPolygon& subject, UniqueSGGeodSet& nodes )
|
||||
{
|
||||
return AddColinearNodes( subject, nodes.get_list() );
|
||||
}
|
||||
|
||||
// this is the opposite of FindColinearNodes - it takes a single SGGeode,
|
||||
// and tries to find the line segment the point is colinear with
|
||||
bool tgPolygon::FindColinearLine( const tgPolygon& subject, SGGeod& node, SGGeod& start, SGGeod& end )
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours() && !found; c++ ) {
|
||||
found = tgContour::FindColinearLine( subject.GetContour(c), node, start, end );
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
SGGeod InterpolateElevation( const SGGeod& dst_node, const SGGeod& start, const SGGeod& end )
|
||||
{
|
||||
double total_dist = SGGeodesy::distanceM( start, end );
|
||||
double inter_dist = SGGeodesy::distanceM( start, dst_node );
|
||||
double delta = inter_dist/total_dist;
|
||||
|
||||
double dest_elevation = start.getElevationM() + (delta * ( end.getElevationM() - start.getElevationM() ));
|
||||
|
||||
return SGGeod::fromDegM( dst_node.getLongitudeDeg(), dst_node.getLatitudeDeg(), dest_elevation );
|
||||
}
|
||||
|
||||
|
||||
void tgPolygon::InheritElevations( const tgPolygon& source )
|
||||
{
|
||||
UniqueSGGeodSet src_nodes;
|
||||
|
||||
// build a list of points from the source polygon
|
||||
for ( unsigned int i = 0; i < source.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < source.ContourSize(i); ++j ) {
|
||||
src_nodes.add( source.GetNode( i, j ) );
|
||||
}
|
||||
}
|
||||
|
||||
// traverse the dest polygon and build a mirror image but with
|
||||
// elevations from the source polygon
|
||||
for ( unsigned int i = 0; i < contours.size(); ++i ) {
|
||||
for ( unsigned int j = 0; j < contours[i].GetSize(); ++j ) {
|
||||
SGGeod dst_node = GetNode(i,j);
|
||||
int index = src_nodes.find( dst_node );
|
||||
if ( index >= 0 ) {
|
||||
SetNode( i, j, src_nodes.get_list()[index] );
|
||||
} else {
|
||||
/* node not is source - we need to find the two points to interpolate from */
|
||||
SGGeod start, end, result;
|
||||
if ( FindColinearLine( source, dst_node, start, end ) ) {
|
||||
dst_node = InterpolateElevation( dst_node, start, end );
|
||||
SetNode( i, j, dst_node );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tgPolygon::Texture( void )
|
||||
{
|
||||
SGGeod p;
|
||||
SGVec2f t;
|
||||
double x, y;
|
||||
float tx, ty;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Texture Poly with material " << material << " method " << tp.method << " tpref " << tp.ref << " heading " << tp.heading );
|
||||
|
||||
switch( tp.method ) {
|
||||
case TG_TEX_BY_GEODE:
|
||||
{
|
||||
// The Simgear General texture coordinate routine takes a fan.
|
||||
// Simgear could probably use a new function that just takes a Geod vector
|
||||
// For now, just create an identity fan...
|
||||
std::vector< int > node_idxs;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
node_idxs.push_back(i);
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < triangles.size(); i++ ) {
|
||||
std::vector< SGVec2f > tc_list;
|
||||
std::vector< SGGeod > nodes;
|
||||
|
||||
nodes = triangles[i].GetNodeList();
|
||||
tc_list = sgCalcTexCoords( tp.center_lat, nodes, node_idxs );
|
||||
triangles[i].SetTexCoordList( tc_list );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TG_TEX_BY_TPS_NOCLIP:
|
||||
case TG_TEX_BY_TPS_CLIPU:
|
||||
case TG_TEX_BY_TPS_CLIPV:
|
||||
case TG_TEX_BY_TPS_CLIPUV:
|
||||
{
|
||||
for ( unsigned int i = 0; i < triangles.size(); i++ ) {
|
||||
for ( unsigned int j = 0; j < 3; j++ ) {
|
||||
p = triangles[i].GetNode( j );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "point = " << p);
|
||||
|
||||
//
|
||||
// 1. Calculate distance and bearing from the center of
|
||||
// the poly
|
||||
//
|
||||
|
||||
// given alt, lat1, lon1, lat2, lon2, calculate starting
|
||||
// and ending az1, az2 and distance (s). Lat, lon, and
|
||||
// azimuth are in degrees. distance in meters
|
||||
double az1, az2, dist;
|
||||
SGGeodesy::inverse( tp.ref, p, az1, az2, dist );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "basic course = " << az2);
|
||||
|
||||
//
|
||||
// 2. Rotate this back into a coordinate system where Y
|
||||
// runs the length of the poly and X runs crossways.
|
||||
//
|
||||
|
||||
double course = SGMiscd::normalizePeriodic(0, 360, az2 - tp.heading);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG," course = " << course << " dist = " << dist );
|
||||
|
||||
//
|
||||
// 3. Convert from polar to cartesian coordinates
|
||||
//
|
||||
|
||||
x = sin( course * SGD_DEGREES_TO_RADIANS ) * dist;
|
||||
y = cos( course * SGD_DEGREES_TO_RADIANS ) * dist;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " x = " << x << " y = " << y);
|
||||
|
||||
//
|
||||
// 4. Map x, y point into texture coordinates
|
||||
//
|
||||
float tmp;
|
||||
|
||||
tmp = (float)x / (float)tp.width;
|
||||
tx = tmp * (float)(tp.maxu - tp.minu) + (float)tp.minu;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")");
|
||||
|
||||
// clip u?
|
||||
if ( (tp.method == TG_TEX_BY_TPS_CLIPU) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
if ( tx < (float)tp.min_clipu ) { tx = (float)tp.min_clipu; }
|
||||
if ( tx > (float)tp.max_clipu ) { tx = (float)tp.max_clipu; }
|
||||
}
|
||||
|
||||
tmp = (float)y / (float)tp.length;
|
||||
ty = tmp * (float)(tp.maxv - tp.minv) + (float)tp.minv;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")");
|
||||
|
||||
// clip v?
|
||||
if ( (tp.method == TG_TEX_BY_TPS_CLIPV) || (tp.method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
if ( ty < (float)tp.min_clipv ) { ty = (float)tp.min_clipv; }
|
||||
if ( ty > (float)tp.max_clipv ) { ty = (float)tp.max_clipv; }
|
||||
}
|
||||
|
||||
t = SGVec2f( tx, ty );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")");
|
||||
|
||||
triangles[i].SetTexCoord( j, t );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tgPolygon::SaveToGzFile( gzFile& fp ) const
|
||||
{
|
||||
// Save the contours
|
||||
sgWriteUInt( fp, contours.size() );
|
||||
for (unsigned int i = 0; i < contours.size(); i++) {
|
||||
contours[i].SaveToGzFile( fp );
|
||||
}
|
||||
|
||||
// Save the triangles
|
||||
sgWriteUInt( fp, triangles.size() );
|
||||
for (unsigned int i = 0; i < triangles.size(); i++) {
|
||||
triangles[i].SaveToGzFile( fp );
|
||||
}
|
||||
|
||||
// Save the tex params
|
||||
tp.SaveToGzFile( fp );
|
||||
|
||||
// and the rest
|
||||
sgWriteString( fp, material.c_str() );
|
||||
sgWriteString( fp, flag.c_str() );
|
||||
sgWriteInt( fp, (int)preserve3d );
|
||||
}
|
||||
|
||||
void tgPolygon::LoadFromGzFile( gzFile& fp )
|
||||
{
|
||||
unsigned int count;
|
||||
tgContour contour;
|
||||
tgTriangle triangle;
|
||||
char *strbuff;
|
||||
|
||||
// Start clean
|
||||
Erase();
|
||||
|
||||
// Load the contours
|
||||
sgReadUInt( fp, &count );
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
contour.LoadFromGzFile( fp );
|
||||
AddContour(contour);
|
||||
}
|
||||
|
||||
// load the triangles
|
||||
sgReadUInt( fp, &count );
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
triangle.LoadFromGzFile( fp );
|
||||
AddTriangle(triangle);
|
||||
}
|
||||
|
||||
// Load the tex params
|
||||
tp.LoadFromGzFile( fp );
|
||||
|
||||
// and the rest
|
||||
sgReadString( fp, &strbuff );
|
||||
if ( strbuff ) {
|
||||
material = strbuff;
|
||||
delete strbuff;
|
||||
}
|
||||
|
||||
sgReadString( fp, &strbuff );
|
||||
if ( strbuff ) {
|
||||
flag = strbuff;
|
||||
delete strbuff;
|
||||
}
|
||||
|
||||
sgReadInt( fp, (int *)&preserve3d );
|
||||
}
|
||||
|
||||
// Friends for serialization
|
||||
std::ostream& operator<< ( std::ostream& output, const tgPolygon& subject )
|
||||
{
|
||||
// Save the data
|
||||
output << "NumContours: " << subject.contours.size() << "\n";
|
||||
|
||||
for( unsigned int c=0; c<subject.contours.size(); c++) {
|
||||
output << subject.contours[c];
|
||||
}
|
||||
|
||||
output << "NumTriangles: " << subject.triangles.size() << "\n";
|
||||
for( unsigned int t=0; t<subject.triangles.size(); t++) {
|
||||
output << subject.triangles[t];
|
||||
}
|
||||
|
||||
output << "Material: " << subject.material;
|
||||
output << "Flag: " << subject.flag;
|
||||
output << subject.tp;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::ostream& operator<< ( std::ostream& output, const tgTriangle& subject )
|
||||
{
|
||||
output << "nodes\n";
|
||||
if ( subject.node_list.size() == 3 ) {
|
||||
output << subject.node_list[0] << ", " << subject.node_list[1] << ", " << subject.node_list[2] << "\n";
|
||||
} else {
|
||||
output << "empty\n";
|
||||
}
|
||||
|
||||
output << "normals\n";
|
||||
if ( subject.norm_list.size() == 3 ) {
|
||||
output << subject.norm_list[0] << ", " << subject.norm_list[1] << ", " << subject.norm_list[2] << "\n";
|
||||
} else {
|
||||
output << "empty\n";
|
||||
}
|
||||
|
||||
output << "texture coords\n";
|
||||
if ( subject.tc_list.size() == 3 ) {
|
||||
output << subject.tc_list[0] << ", " << subject.tc_list[1] << ", " << subject.tc_list[2] << "\n";
|
||||
} else {
|
||||
output << "empty\n";
|
||||
}
|
||||
|
||||
output << "node indexes\n";
|
||||
if ( subject.idx_list.size() == 3 ) {
|
||||
output << subject.idx_list[0] << ", " << subject.idx_list[1] << ", " << subject.idx_list[2] << "\n";
|
||||
} else {
|
||||
output << "empty\n";
|
||||
}
|
||||
|
||||
output << "Face normal: " << subject.face_normal << "\n";
|
||||
output << "Face area: " << subject.face_area << "\n";
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void tgTriangle::SaveToGzFile( gzFile& fp ) const
|
||||
{
|
||||
// Save the three nodes, and their attributes
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
sgWriteGeod( fp, node_list[i] );
|
||||
// sgWriteVec2( fp, tc_list[i] );
|
||||
// sgWritedVec3( fp, norm_list[i] ); // not calculated until stage 3
|
||||
sgWriteInt( fp, idx_list[i] );
|
||||
}
|
||||
}
|
||||
|
||||
void tgTriangle::LoadFromGzFile( gzFile& fp )
|
||||
{
|
||||
// Load the nodelist
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
sgReadGeod( fp, node_list[i] );
|
||||
// sgReadVec2( fp, tc_list[i] );
|
||||
// sgReaddVec3( fp, norm_list[i] );
|
||||
sgReadInt( fp, &idx_list[i] );
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<< ( std::ostream& output, const tgTexParams& subject )
|
||||
{
|
||||
// Save the data
|
||||
output << "Ref : " << subject.ref;
|
||||
output << "Width : " << subject.width;
|
||||
output << "Length : " << subject.length;
|
||||
output << "Heading: " << subject.heading;
|
||||
|
||||
output << "u: (" << subject.minu << "," << subject.maxu << ")";
|
||||
output << "v: (" << subject.minv << "," << subject.maxv << ")";
|
||||
|
||||
output << "method: " << subject.method;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void tgTexParams::SaveToGzFile( gzFile& fp ) const
|
||||
{
|
||||
// Save the parameters
|
||||
sgWriteInt( fp, (int)method );
|
||||
|
||||
if ( method == TG_TEX_BY_GEODE ) {
|
||||
sgWriteDouble( fp, center_lat );
|
||||
} else {
|
||||
sgWriteGeod( fp, ref );
|
||||
sgWriteDouble( fp, width );
|
||||
sgWriteDouble( fp, length );
|
||||
sgWriteDouble( fp, heading );
|
||||
|
||||
sgWriteDouble( fp, minu );
|
||||
sgWriteDouble( fp, maxu );
|
||||
sgWriteDouble( fp, minv );
|
||||
sgWriteDouble( fp, maxv );
|
||||
|
||||
if ( (method == TG_TEX_BY_TPS_CLIPU) ||
|
||||
(method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
sgWriteDouble( fp, min_clipu );
|
||||
sgWriteDouble( fp, max_clipu );
|
||||
}
|
||||
|
||||
if ( (method == TG_TEX_BY_TPS_CLIPV) ||
|
||||
(method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
sgWriteDouble( fp, min_clipv );
|
||||
sgWriteDouble( fp, max_clipv );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tgTexParams::LoadFromGzFile( gzFile& fp )
|
||||
{
|
||||
// Load the parameters
|
||||
sgReadInt( fp, (int*)&method );
|
||||
|
||||
if ( method == TG_TEX_BY_GEODE ) {
|
||||
sgReadDouble( fp, ¢er_lat );
|
||||
} else {
|
||||
sgReadGeod( fp, ref );
|
||||
sgReadDouble( fp, &width );
|
||||
sgReadDouble( fp, &length );
|
||||
sgReadDouble( fp, &heading );
|
||||
|
||||
sgReadDouble( fp, &minu );
|
||||
sgReadDouble( fp, &maxu );
|
||||
sgReadDouble( fp, &minv );
|
||||
sgReadDouble( fp, &maxv );
|
||||
|
||||
if ( (method == TG_TEX_BY_TPS_CLIPU) ||
|
||||
(method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
sgReadDouble( fp, &min_clipu );
|
||||
sgReadDouble( fp, &max_clipu );
|
||||
}
|
||||
|
||||
if ( (method == TG_TEX_BY_TPS_CLIPV) ||
|
||||
(method == TG_TEX_BY_TPS_CLIPUV) ) {
|
||||
sgReadDouble( fp, &min_clipv );
|
||||
sgReadDouble( fp, &max_clipv );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@
|
|||
#ifndef _POLYGON_HXX
|
||||
#define _POLYGON_HXX
|
||||
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
@ -56,15 +55,13 @@
|
|||
// For the first attempt, I will just have TGPolygon with a list of contours.
|
||||
// the extra data are stored in paralell vectors.
|
||||
// This should also make TGSuperPoly obsolete
|
||||
#include <ogrsf_frmts.h>
|
||||
#include <boost/concept_check.hpp>
|
||||
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
|
||||
#include <Polygon/rectangle.hxx>
|
||||
|
||||
#include "tg_unique_geod.hxx"
|
||||
#include "tg_rectangle.hxx"
|
||||
#include "tg_contour.hxx"
|
||||
|
||||
// utilities - belong is simgear?
|
||||
double CalculateTheta( const SGVec3d& dirCur, const SGVec3d& dirNext, const SGVec3d& cp );
|
||||
|
@ -89,98 +86,6 @@ typedef std::vector <tgPolygon> tgpolygon_list;
|
|||
typedef tgpolygon_list::iterator tgpolygon_list_iterator;
|
||||
typedef tgpolygon_list::const_iterator const_tgpolygon_list_iterator;
|
||||
|
||||
class tgContour
|
||||
{
|
||||
public:
|
||||
tgContour() {
|
||||
hole = false;
|
||||
}
|
||||
|
||||
void Erase() {
|
||||
node_list.clear();
|
||||
}
|
||||
|
||||
void SetHole( bool h ) {
|
||||
hole = h;
|
||||
}
|
||||
bool GetHole( void ) const {
|
||||
return hole;
|
||||
}
|
||||
|
||||
unsigned int GetSize( void ) const {
|
||||
return node_list.size();
|
||||
}
|
||||
|
||||
void Resize( int size ) {
|
||||
node_list.resize( size );
|
||||
}
|
||||
|
||||
void AddNode( SGGeod n ) {
|
||||
node_list.push_back( n );
|
||||
}
|
||||
void SetNode( unsigned int i, SGGeod n ) {
|
||||
node_list[i] = n;
|
||||
}
|
||||
SGGeod GetNode( unsigned int i ) const {
|
||||
return node_list[i];
|
||||
}
|
||||
SGGeod const& operator[]( int index ) const {
|
||||
return node_list[index];
|
||||
}
|
||||
|
||||
void RemoveNodeAt( unsigned int idx ) {
|
||||
if ( idx < node_list.size() ) {
|
||||
node_list.erase( node_list.begin() + idx );
|
||||
}
|
||||
}
|
||||
void RemoveNodeRange( unsigned int from, unsigned int to ) {
|
||||
if ( ( from < to ) && ( to < node_list.size() ) ) {
|
||||
node_list.erase( node_list.begin()+from,node_list.begin()+to );
|
||||
}
|
||||
}
|
||||
|
||||
tgRectangle GetBoundingBox( void ) const;
|
||||
|
||||
double GetMinimumAngle( void ) const;
|
||||
double GetArea( void ) const;
|
||||
|
||||
static tgContour Snap( const tgContour& subject, double snap );
|
||||
static tgContour RemoveDups( const tgContour& subject );
|
||||
static tgContour RemoveCycles( const tgContour& subject );
|
||||
static tgContour SplitLongEdges( const tgContour& subject, double dist );
|
||||
static tgContour RemoveSpikes( const tgContour& subject );
|
||||
|
||||
static tgPolygon Union( const tgContour& subject, tgPolygon& clip );
|
||||
static tgPolygon Diff( const tgContour& subject, tgPolygon& clip );
|
||||
|
||||
static tgContour AddColinearNodes( const tgContour& subject, UniqueSGGeodSet& nodes );
|
||||
static tgContour AddColinearNodes( const tgContour& subject, std::vector<SGGeod>& nodes );
|
||||
static bool FindColinearLine( const tgContour& subject, const SGGeod& node, SGGeod& start, SGGeod& end );
|
||||
|
||||
// conversions
|
||||
static ClipperLib::Polygon ToClipper( const tgContour& subject );
|
||||
static tgContour FromClipper( const ClipperLib::Polygon& subject );
|
||||
|
||||
static tgContour Expand( const tgContour& subject, double offset );
|
||||
static tgpolygon_list ExpandToPolygons( const tgContour& subject, double width );
|
||||
|
||||
static void ToShapefile( const tgContour& subject, const std::string& datasource, const std::string& layer, const std::string& feature );
|
||||
|
||||
void SaveToGzFile( gzFile& fp ) const;
|
||||
void LoadFromGzFile( gzFile& fp );
|
||||
|
||||
// Friend for output
|
||||
friend std::ostream& operator<< ( std::ostream&, const tgContour& );
|
||||
|
||||
private:
|
||||
std::vector<SGGeod> node_list;
|
||||
bool hole;
|
||||
};
|
||||
|
||||
typedef std::vector <tgContour> tgcontour_list;
|
||||
typedef tgcontour_list::iterator tgcontour_list_iterator;
|
||||
typedef tgcontour_list::const_iterator const_tgcontour_list_iterator;
|
||||
|
||||
class tgTriangle
|
||||
{
|
||||
public:
|
||||
|
@ -410,7 +315,7 @@ public:
|
|||
void SetPreserve3D( bool p ) {
|
||||
preserve3d = p;
|
||||
}
|
||||
|
||||
|
||||
unsigned int GetId( void ) const {
|
||||
return id;
|
||||
}
|
||||
|
@ -418,6 +323,8 @@ public:
|
|||
id = i;
|
||||
}
|
||||
|
||||
|
||||
// Texturing
|
||||
void SetTexParams( const SGGeod& ref, double width, double length, double heading ) {
|
||||
tp.ref = ref;
|
||||
tp.width = width;
|
||||
|
@ -455,62 +362,50 @@ public:
|
|||
tgTexMethod GetTexMethod( void ) const {
|
||||
return tp.method;
|
||||
}
|
||||
void Texture( void );
|
||||
|
||||
// Tesselation
|
||||
void Tesselate( void );
|
||||
void Tesselate( const std::vector<SGGeod>& extra );
|
||||
|
||||
void Texture( void );
|
||||
|
||||
// Boolean operations
|
||||
|
||||
// TODO : Both should be constant
|
||||
// what we really need is multiple accumulators
|
||||
// init_accumulator should return a handle...
|
||||
static bool ChopIdxInit( const std::string& path );
|
||||
|
||||
static void SetDump( bool dmp );
|
||||
static tgPolygon Union( const tgContour& subject, tgPolygon& clip );
|
||||
static void SetClipperDump( bool dmp );
|
||||
static tgPolygon Union( const tgPolygon& subject, tgPolygon& clip );
|
||||
static tgPolygon Union( const tgpolygon_list& polys );
|
||||
static tgPolygon Diff( const tgPolygon& subject, tgPolygon& clip );
|
||||
static tgPolygon Intersect( const tgPolygon& subject, const tgPolygon& clip );
|
||||
|
||||
// Conversions
|
||||
static ClipperLib::Polygons ToClipper( const tgPolygon& subject );
|
||||
static tgPolygon FromClipper( const ClipperLib::Polygons& subject );
|
||||
|
||||
static tgPolygon FromOGR( const OGRPolygon* subject );
|
||||
|
||||
// other operations
|
||||
// cleanup operations
|
||||
static tgPolygon Snap( const tgPolygon& subject, double snap );
|
||||
static tgPolygon StripHoles( const tgPolygon& subject );
|
||||
static tgPolygon SplitLongEdges( const tgPolygon& subject, double dist );
|
||||
|
||||
static tgPolygon RemoveCycles( const tgPolygon& subject );
|
||||
static tgPolygon RemoveDups( const tgPolygon& subject );
|
||||
static tgPolygon RemoveBadContours( const tgPolygon& subject );
|
||||
static tgPolygon Simplify( const tgPolygon& subject );
|
||||
static tgPolygon RemoveTinyContours( const tgPolygon& subject );
|
||||
static tgPolygon RemoveSpikes( const tgPolygon& subject );
|
||||
static void RemoveSlivers( tgPolygon& subject, tgcontour_list& slivers );
|
||||
static tgcontour_list MergeSlivers( tgpolygon_list& subjects, tgcontour_list& slivers );
|
||||
|
||||
static tgPolygon Expand( const tgPolygon& subject, double offset );
|
||||
static tgPolygon Expand( const SGGeod& subject, double offset );
|
||||
|
||||
|
||||
// Conversions
|
||||
static ClipperLib::Polygons ToClipper( const tgPolygon& subject );
|
||||
static tgPolygon FromClipper( const ClipperLib::Polygons& subject );
|
||||
|
||||
static void ToShapefile( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& feature );
|
||||
|
||||
static void Tesselate( const tgPolygon& subject );
|
||||
|
||||
// T-Junctions and segment search
|
||||
static tgPolygon AddColinearNodes( const tgPolygon& subject, UniqueSGGeodSet& nodes );
|
||||
static tgPolygon AddColinearNodes( const tgPolygon& subject, std::vector<SGGeod>& nodes );
|
||||
static bool FindColinearLine( const tgPolygon& subject, SGGeod& node, SGGeod& start, SGGeod& end );
|
||||
|
||||
static void RemoveSlivers( tgPolygon& subject, tgcontour_list& slivers );
|
||||
static tgcontour_list MergeSlivers( tgpolygon_list& subjects, tgcontour_list& slivers );
|
||||
|
||||
// IO
|
||||
void SaveToGzFile( gzFile& fp ) const;
|
||||
void LoadFromGzFile( gzFile& fp );
|
||||
|
||||
// Friend for output
|
||||
friend std::ostream& operator<< ( std::ostream&, const tgPolygon& );
|
||||
|
||||
private:
|
||||
|
@ -524,143 +419,4 @@ private:
|
|||
tgTexParams tp;
|
||||
};
|
||||
|
||||
// for ogr-decode : generate a bunch of polygons, mapped by bucket id
|
||||
typedef std::map<long int, tgpolygon_list> bucket_polys_map;
|
||||
typedef bucket_polys_map::iterator bucket_polys_map_interator;
|
||||
|
||||
class tgChopper
|
||||
{
|
||||
public:
|
||||
tgChopper( const std::string& path ) {
|
||||
root_path = path;
|
||||
}
|
||||
|
||||
void Add( const tgPolygon& poly, const std::string& type );
|
||||
void Save( void );
|
||||
|
||||
private:
|
||||
long int GenerateIndex( std::string path );
|
||||
void Clip( const tgPolygon& subject, const std::string& type, SGBucket& b );
|
||||
void Chop( const tgPolygon& subject, const std::string& type );
|
||||
|
||||
std::string root_path;
|
||||
bucket_polys_map bp_map;
|
||||
SGMutex lock;
|
||||
};
|
||||
|
||||
class tgLight
|
||||
{
|
||||
public:
|
||||
SGGeod pos;
|
||||
SGVec3f norm;
|
||||
};
|
||||
|
||||
typedef std::vector <tgLight> tglight_list;
|
||||
typedef tglight_list::iterator tglight_list_iterator;
|
||||
typedef tglight_list::const_iterator const_tglight_list_iterator;
|
||||
|
||||
class tgLightContour
|
||||
{
|
||||
public:
|
||||
unsigned int ContourSize( void ) const {
|
||||
return lights.size();
|
||||
}
|
||||
|
||||
void AddLight( SGGeod p, SGVec3f n ) {
|
||||
tgLight light;
|
||||
light.pos = p;
|
||||
light.norm = n;
|
||||
lights.push_back(light);
|
||||
}
|
||||
|
||||
void SetElevation( unsigned int i, double elev ) {
|
||||
lights[i].pos.setElevationM( elev );
|
||||
}
|
||||
|
||||
SGGeod GetNode( unsigned int i ) const {
|
||||
return lights[i].pos;
|
||||
}
|
||||
|
||||
SGGeod GetPosition( unsigned int i ) const {
|
||||
return lights[i].pos;
|
||||
}
|
||||
|
||||
SGVec3f GetNormal( unsigned int i ) const {
|
||||
return lights[i].norm;
|
||||
}
|
||||
|
||||
std::string GetFlag( void ) const {
|
||||
return flag;
|
||||
}
|
||||
void SetFlag( const std::string f ) {
|
||||
flag = f;
|
||||
}
|
||||
|
||||
std::string GetType( void ) const {
|
||||
return type;
|
||||
}
|
||||
void SetType( const std::string t ) {
|
||||
type = t;
|
||||
}
|
||||
|
||||
std::vector<SGGeod> GetPositionList( void ) {
|
||||
std::vector<SGGeod> positions;
|
||||
|
||||
for (unsigned int i=0; i<lights.size(); i++) {
|
||||
positions.push_back( lights[i].pos );
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
std::vector<SGVec3f> GetNormalList( void ) {
|
||||
std::vector<SGVec3f> normals;
|
||||
|
||||
for (unsigned int i=0; i<lights.size(); i++) {
|
||||
normals.push_back( lights[i].norm );
|
||||
}
|
||||
|
||||
return normals;
|
||||
}
|
||||
|
||||
// Friend for output
|
||||
friend std::ostream& operator<< ( std::ostream&, const tgLightContour& );
|
||||
|
||||
std::string type;
|
||||
std::string flag;
|
||||
tglight_list lights;
|
||||
};
|
||||
|
||||
typedef std::vector <tgLightContour> tglightcontour_list;
|
||||
typedef tglightcontour_list::iterator tglightcontour_list_iterator;
|
||||
typedef tglightcontour_list::const_iterator const_tglightcontour_list_iterator;
|
||||
|
||||
typedef std::vector < ClipperLib::Polygons > clipper_polygons_list;
|
||||
|
||||
class tgAccumulator
|
||||
{
|
||||
public:
|
||||
tgPolygon Diff( const tgContour& subject );
|
||||
tgPolygon Diff( const tgPolygon& subject );
|
||||
|
||||
void Add( const tgContour& subject );
|
||||
void Add( const tgPolygon& subject );
|
||||
|
||||
void ToShapefiles( const std::string& path, const std::string& layer );
|
||||
|
||||
private:
|
||||
clipper_polygons_list accum;
|
||||
};
|
||||
|
||||
class tgShapefile
|
||||
{
|
||||
public:
|
||||
static void Init( void );
|
||||
static void* OpenDatasource( const char* datasource_name );
|
||||
static void* OpenLayer( void* ds_id, const char* layer_name );
|
||||
// static void CreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, const char* description );
|
||||
static void CloseLayer( void* l_id );
|
||||
static void* CloseDatasource( void* ds_id );
|
||||
};
|
||||
|
||||
#endif // _POLYGON_HXX
|
272
src/Lib/terragear/tg_polygon_clean.cxx
Normal file
272
src/Lib/terragear/tg_polygon_clean.cxx
Normal file
|
@ -0,0 +1,272 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
tgPolygon tgPolygon::Snap( const tgPolygon& subject, double snap )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for (unsigned int c = 0; c < subject.Contours(); c++) {
|
||||
result.AddContour( tgContour::Snap( subject.GetContour( c ), snap ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::RemoveDups( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
result.AddContour( tgContour::RemoveDups( subject.GetContour( c ) ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::RemoveBadContours( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
tgContour contour = subject.GetContour(c);
|
||||
if ( contour.GetSize() >= 3 ) {
|
||||
/* keeping the contour */
|
||||
result.AddContour( contour );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::RemoveCycles( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
result.AddContour( tgContour::RemoveCycles( subject.GetContour( c ) ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::SplitLongEdges( const tgPolygon& subject, double dist )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned c = 0; c < subject.Contours(); c++ )
|
||||
{
|
||||
result.AddContour( tgContour::SplitLongEdges( subject.GetContour(c), dist ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::StripHoles( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
ClipperLib::Polygons clipper_result;
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
|
||||
for ( unsigned int i = 0; i < subject.Contours(); i++ ) {
|
||||
tgContour contour = subject.GetContour( i );
|
||||
if ( !contour.GetHole() ) {
|
||||
c.AddPolygon( tgContour::ToClipper( contour ), ClipperLib::ptClip );
|
||||
}
|
||||
}
|
||||
c.Execute(ClipperLib::ctUnion, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Simplify( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
ClipperLib::Polygons clipper_poly = tgPolygon::ToClipper( subject );
|
||||
SimplifyPolygons( clipper_poly );
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_poly );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::RemoveTinyContours( const tgPolygon& subject )
|
||||
{
|
||||
double min_area = SG_EPSILON*SG_EPSILON;
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
tgContour contour = subject.GetContour( c );
|
||||
double area = contour.GetArea();
|
||||
|
||||
if ( area >= min_area) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_tiny_contours NO - " << c << " area is " << area << " requirement is " << min_area);
|
||||
result.AddContour( contour );
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "remove_tiny_contours " << c << " area is " << area << ": removing");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::RemoveSpikes( const tgPolygon& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
for ( unsigned int c = 0; c < subject.Contours(); c++ ) {
|
||||
result.AddContour( tgContour::RemoveSpikes( subject.GetContour(c) ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Move slivers from in polygon to out polygon.
|
||||
void tgPolygon::RemoveSlivers( tgPolygon& subject, tgcontour_list& slivers )
|
||||
{
|
||||
#if 0
|
||||
// traverse each contour of the polygon and attempt to identify
|
||||
// likely slivers
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "tgPolygon::RemoveSlivers()");
|
||||
|
||||
tgPolygon result;
|
||||
tgContour contour;
|
||||
int i;
|
||||
|
||||
double angle_cutoff = 10.0 * SGD_DEGREES_TO_RADIANS;
|
||||
double area_cutoff = 0.000000001;
|
||||
double min_angle;
|
||||
double area;
|
||||
|
||||
// process contours in reverse order so deleting a contour doesn't
|
||||
// foul up our sequence
|
||||
for ( i = subject.Contours() - 1; i >= 0; --i ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "contour " << i );
|
||||
|
||||
contour = subject.GetContour(i);
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " calc min angle for contour " << i);
|
||||
min_angle = contour.GetMinimumAngle();
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " min_angle (rad) = " << min_angle );
|
||||
|
||||
area = contour.GetArea();
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " area = " << area );
|
||||
|
||||
if ( ((min_angle < angle_cutoff) && (area < area_cutoff)) ||
|
||||
( area < area_cutoff / 10.0) )
|
||||
{
|
||||
if ((min_angle < angle_cutoff) && (area < area_cutoff))
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " WE THINK IT'S A SLIVER! - min angle < 10 deg, and area < 10 sq meters");
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " WE THINK IT'S A SLIVER! - min angle > 10 deg, but area < 1 sq meters");
|
||||
}
|
||||
|
||||
// Remove the sliver from source
|
||||
subject.DeleteContourAt( i );
|
||||
|
||||
// And add it to the slive list if it isn't a hole
|
||||
if ( !contour.GetHole() ) {
|
||||
// move sliver contour to sliver list
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " Found SLIVER!");
|
||||
|
||||
slivers.push_back( contour );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
tgcontour_list tgPolygon::MergeSlivers( tgpolygon_list& polys, tgcontour_list& sliver_list ) {
|
||||
tgPolygon poly, result;
|
||||
tgContour sliver;
|
||||
tgContour contour;
|
||||
tgcontour_list unmerged;
|
||||
unsigned int original_contours, result_contours;
|
||||
bool done;
|
||||
|
||||
for ( unsigned int i = 0; i < sliver_list.size(); i++ ) {
|
||||
sliver = sliver_list[i];
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Merging sliver = " << i );
|
||||
|
||||
sliver.SetHole( false );
|
||||
|
||||
done = false;
|
||||
|
||||
// try to merge the slivers with the list of clipped polys
|
||||
for ( unsigned int j = 0; j < polys.size() && !done; j++ ) {
|
||||
poly = polys[j];
|
||||
original_contours = poly.Contours();
|
||||
result = tgContour::Union( sliver, poly );
|
||||
result_contours = result.Contours();
|
||||
|
||||
if ( original_contours == result_contours ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, " FOUND a poly to merge the sliver with");
|
||||
result.SetMaterial( polys[j].GetMaterial() );
|
||||
result.SetTexParams( polys[j].GetTexParams() );
|
||||
polys[j] = result;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !done ) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "couldn't merge sliver " << i );
|
||||
unmerged.push_back( sliver );
|
||||
}
|
||||
}
|
||||
|
||||
return unmerged;
|
||||
}
|
||||
|
175
src/Lib/terragear/tg_polygon_clip.cxx
Normal file
175
src/Lib/terragear/tg_polygon_clip.cxx
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
static bool clipper_dump = false;
|
||||
void tgPolygon::SetClipperDump( bool dmp )
|
||||
{
|
||||
clipper_dump = dmp;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Union( const tgPolygon& subject, tgPolygon& clip )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
std::ofstream dmpfile;
|
||||
|
||||
/* before union - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( clip );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
if ( clipper_dump ) {
|
||||
dmpfile.open ("subject.txt");
|
||||
dmpfile << clipper_subject;
|
||||
dmpfile.close();
|
||||
|
||||
dmpfile.open ("clip.txt");
|
||||
dmpfile << clipper_clip;
|
||||
dmpfile.close();
|
||||
}
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
|
||||
c.Execute(ClipperLib::ctUnion, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
if ( clipper_dump ) {
|
||||
dmpfile.open ("result.txt");
|
||||
dmpfile << clipper_result;
|
||||
dmpfile.close();
|
||||
}
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Union( const tgpolygon_list& polys )
|
||||
{
|
||||
ClipperLib::Polygons clipper_result;
|
||||
ClipperLib::Clipper c;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
tgPolygon result;
|
||||
|
||||
/* before union - gather all nodes */
|
||||
for ( unsigned int i=0; i<polys.size(); i++ ) {
|
||||
for ( unsigned int j = 0; j < polys[i].Contours(); ++j ) {
|
||||
for ( unsigned int k = 0; k < polys[i].ContourSize( j ); ++k ) {
|
||||
all_nodes.add( polys[i].GetNode(j, k) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.Clear();
|
||||
for (unsigned int i=0; i<polys.size(); i++) {
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( polys[i] );
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptSubject);
|
||||
}
|
||||
c.Execute(ClipperLib::ctUnion, clipper_result, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Diff( const tgPolygon& subject, tgPolygon& clip )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before diff - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( clip );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
|
||||
c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::Intersect( const tgPolygon& subject, const tgPolygon& clip )
|
||||
{
|
||||
tgPolygon result;
|
||||
UniqueSGGeodSet all_nodes;
|
||||
|
||||
/* before intersect - gather all nodes */
|
||||
for ( unsigned int i = 0; i < subject.Contours(); ++i ) {
|
||||
for ( unsigned int j = 0; j < subject.ContourSize( i ); ++j ) {
|
||||
all_nodes.add( subject.GetNode(i, j) );
|
||||
}
|
||||
}
|
||||
|
||||
ClipperLib::Polygons clipper_subject = tgPolygon::ToClipper( subject );
|
||||
ClipperLib::Polygons clipper_clip = tgPolygon::ToClipper( clip );
|
||||
ClipperLib::Polygons clipper_result;
|
||||
|
||||
ClipperLib::Clipper c;
|
||||
c.Clear();
|
||||
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
|
||||
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
|
||||
c.Execute(ClipperLib::ctIntersection, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
|
||||
|
||||
result = tgPolygon::FromClipper( clipper_result );
|
||||
result = tgPolygon::AddColinearNodes( result, all_nodes );
|
||||
|
||||
result.SetMaterial( subject.GetMaterial() );
|
||||
result.SetTexParams( subject.GetTexParams() );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ClipperLib::Polygons tgPolygon::ToClipper( const tgPolygon& subject )
|
||||
{
|
||||
ClipperLib::Polygons result;
|
||||
|
||||
for ( unsigned int i=0; i<subject.Contours(); i++ ) {
|
||||
result.push_back( tgContour::ToClipper( subject.GetContour(i) ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tgPolygon tgPolygon::FromClipper( const ClipperLib::Polygons& subject )
|
||||
{
|
||||
tgPolygon result;
|
||||
|
||||
// for each polygon, we need to check the orientation, to set the hole flag...
|
||||
for ( unsigned int i=0; i<subject.size(); i++)
|
||||
{
|
||||
result.AddContour( tgContour::FromClipper( subject[i] ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
194
src/Lib/terragear/tg_polygon_tesselate.cxx
Normal file
194
src/Lib/terragear/tg_polygon_tesselate.cxx
Normal file
|
@ -0,0 +1,194 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_face_base_with_info_2.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Triangle_2.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
/* determining if a face is within the reulting poly */
|
||||
struct FaceInfo2
|
||||
{
|
||||
FaceInfo2() {}
|
||||
int nesting_level;
|
||||
|
||||
bool in_domain(){
|
||||
return nesting_level%2 == 1;
|
||||
}
|
||||
};
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Triangulation_vertex_base_2<K> Vb;
|
||||
typedef CGAL::Triangulation_face_base_with_info_2<FaceInfo2,K> Fbb;
|
||||
typedef CGAL::Constrained_triangulation_face_base_2<K,Fbb> Fb;
|
||||
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
|
||||
typedef CGAL::Exact_predicates_tag Itag;
|
||||
typedef CGAL::Constrained_Delaunay_triangulation_2<K, TDS, Itag> CDT;
|
||||
typedef CDT::Point Point;
|
||||
typedef CGAL::Polygon_2<K> Polygon_2;
|
||||
typedef CGAL::Triangle_2<K> Triangle_2;
|
||||
|
||||
static void tg_mark_domains(CDT& ct, CDT::Face_handle start, int index, std::list<CDT::Edge>& border )
|
||||
{
|
||||
if(start->info().nesting_level != -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<CDT::Face_handle> queue;
|
||||
queue.push_back(start);
|
||||
|
||||
while( !queue.empty() ){
|
||||
CDT::Face_handle fh = queue.front();
|
||||
queue.pop_front();
|
||||
if(fh->info().nesting_level == -1) {
|
||||
fh->info().nesting_level = index;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
CDT::Edge e(fh,i);
|
||||
CDT::Face_handle n = fh->neighbor(i);
|
||||
if(n->info().nesting_level == -1) {
|
||||
if(ct.is_constrained(e)) border.push_back(e);
|
||||
else queue.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//explore set of facets connected with non constrained edges,
|
||||
//and attribute to each such set a nesting level.
|
||||
//We start from facets incident to the infinite vertex, with a nesting
|
||||
//level of 0. Then we recursively consider the non-explored facets incident
|
||||
//to constrained edges bounding the former set and increase the nesting level by 1.
|
||||
//Facets in the domain are those with an odd nesting level.
|
||||
static void tg_mark_domains(CDT& cdt)
|
||||
{
|
||||
for(CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it){
|
||||
it->info().nesting_level = -1;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
std::list<CDT::Edge> border;
|
||||
tg_mark_domains(cdt, cdt.infinite_face(), index++, border);
|
||||
while(! border.empty()) {
|
||||
CDT::Edge e = border.front();
|
||||
border.pop_front();
|
||||
CDT::Face_handle n = e.first->neighbor(e.second);
|
||||
if(n->info().nesting_level == -1) {
|
||||
tg_mark_domains(cdt, n, e.first->info().nesting_level+1, border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tg_insert_polygon(CDT& cdt,const Polygon_2& polygon)
|
||||
{
|
||||
if ( polygon.is_empty() ) return;
|
||||
|
||||
CDT::Vertex_handle v_prev=cdt.insert(*CGAL::cpp0x::prev(polygon.vertices_end()));
|
||||
for (Polygon_2::Vertex_iterator vit=polygon.vertices_begin(); vit!=polygon.vertices_end();++vit) {
|
||||
CDT::Vertex_handle vh=cdt.insert(*vit);
|
||||
cdt.insert_constraint(vh,v_prev);
|
||||
v_prev=vh;
|
||||
}
|
||||
}
|
||||
|
||||
void tgPolygon::Tesselate( const std::vector<SGGeod>& extra )
|
||||
{
|
||||
CDT cdt;
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess with extra" );
|
||||
|
||||
// Bail right away if polygon is empty
|
||||
if ( contours.size() != 0 ) {
|
||||
// First, convert the extra points to cgal Points
|
||||
std::vector<Point> points;
|
||||
points.reserve(extra.size());
|
||||
for (unsigned int n = 0; n < extra.size(); n++) {
|
||||
points.push_back( Point(extra[n].getLongitudeDeg(), extra[n].getLatitudeDeg() ) );
|
||||
}
|
||||
|
||||
cdt.insert(points.begin(), points.end());
|
||||
|
||||
// then insert each polygon as a constraint into the triangulation
|
||||
for ( unsigned int c = 0; c < contours.size(); c++ ) {
|
||||
tgContour contour = contours[c];
|
||||
Polygon_2 poly;
|
||||
|
||||
for (unsigned int n = 0; n < contour.GetSize(); n++ ) {
|
||||
SGGeod node = contour.GetNode(n);
|
||||
poly.push_back( Point( node.getLongitudeDeg(), node.getLatitudeDeg() ) );
|
||||
}
|
||||
|
||||
tg_insert_polygon(cdt, poly);
|
||||
}
|
||||
|
||||
tg_mark_domains( cdt );
|
||||
|
||||
int count=0;
|
||||
for (CDT::Finite_faces_iterator fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); ++fit) {
|
||||
if ( fit->info().in_domain() ) {
|
||||
Triangle_2 tri = cdt.triangle(fit);
|
||||
|
||||
SGGeod p0 = SGGeod::fromDeg( tri.vertex(0).x(), tri.vertex(0).y() );
|
||||
SGGeod p1 = SGGeod::fromDeg( tri.vertex(1).x(), tri.vertex(1).y() );
|
||||
SGGeod p2 = SGGeod::fromDeg( tri.vertex(2).x(), tri.vertex(2).y() );
|
||||
|
||||
AddTriangle( p0, p1, p2 );
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tgPolygon::Tesselate()
|
||||
{
|
||||
CDT cdt;
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess" );
|
||||
|
||||
// Bail right away if polygon is empty
|
||||
if ( contours.size() != 0 ) {
|
||||
// insert each polygon as a constraint into the triangulation
|
||||
for ( unsigned int c = 0; c < contours.size(); c++ ) {
|
||||
tgContour contour = contours[c];
|
||||
Polygon_2 poly;
|
||||
|
||||
for (unsigned int n = 0; n < contour.GetSize(); n++ ) {
|
||||
SGGeod node = contour.GetNode(n);
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess : Adding GEOD " << node);
|
||||
poly.push_back( Point( node.getLongitudeDeg(), node.getLatitudeDeg() ) );
|
||||
}
|
||||
|
||||
tg_insert_polygon(cdt, poly);
|
||||
}
|
||||
|
||||
tg_mark_domains( cdt );
|
||||
|
||||
int count=0;
|
||||
for (CDT::Finite_faces_iterator fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); ++fit) {
|
||||
if ( fit->info().in_domain() ) {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess : face in domain");
|
||||
|
||||
Triangle_2 tri = cdt.triangle(fit);
|
||||
|
||||
SGGeod p0 = SGGeod::fromDeg( tri.vertex(0).x(), tri.vertex(0).y() );
|
||||
SGGeod p1 = SGGeod::fromDeg( tri.vertex(1).x(), tri.vertex(1).y() );
|
||||
SGGeod p2 = SGGeod::fromDeg( tri.vertex(2).x(), tri.vertex(2).y() );
|
||||
|
||||
AddTriangle( p0, p1, p2 );
|
||||
|
||||
++count;
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess : face not in domain");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "Tess : no contours" );
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#include "rectangle.hxx"
|
||||
#include "tg_rectangle.hxx"
|
||||
|
||||
tgRectangle::tgRectangle()
|
||||
{
|
208
src/Lib/terragear/tg_shapefile.cxx
Normal file
208
src/Lib/terragear/tg_shapefile.cxx
Normal file
|
@ -0,0 +1,208 @@
|
|||
#include <ogrsf_frmts.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "tg_misc.hxx"
|
||||
#include "tg_shapefile.hxx"
|
||||
|
||||
bool tgShapefile::initialized = false;
|
||||
|
||||
void* tgShapefile::OpenDatasource( const char* datasource_name )
|
||||
{
|
||||
OGRDataSource* datasource;
|
||||
OGRSFDriver* ogrdriver;
|
||||
const char* format_name = "ESRI Shapefile";
|
||||
|
||||
if (!tgShapefile::initialized) {
|
||||
OGRRegisterAll();
|
||||
tgShapefile::initialized = true;
|
||||
}
|
||||
|
||||
ogrdriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName( format_name );
|
||||
if ( !ogrdriver ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unknown datasource format driver: " << format_name );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
datasource = ogrdriver->Open( datasource_name, TRUE );
|
||||
if ( !datasource ) {
|
||||
datasource = ogrdriver->CreateDataSource( datasource_name, NULL );
|
||||
}
|
||||
|
||||
if ( !datasource ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Unable to open or create datasource: " << datasource_name );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (void*)datasource;
|
||||
}
|
||||
|
||||
void* tgShapefile::OpenLayer( void* ds_id, const char* layer_name ) {
|
||||
OGRDataSource* datasource = ( OGRDataSource * )ds_id;
|
||||
OGRLayer* layer;
|
||||
|
||||
OGRSpatialReference srs;
|
||||
srs.SetWellKnownGeogCS("WGS84");
|
||||
|
||||
layer = datasource->GetLayerByName( layer_name );
|
||||
|
||||
if ( !layer ) {
|
||||
layer = datasource->CreateLayer( layer_name, &srs, wkbPolygon25D, NULL );
|
||||
|
||||
OGRFieldDefn descriptionField( "ID", OFTString );
|
||||
descriptionField.SetWidth( 128 );
|
||||
|
||||
if( layer->CreateField( &descriptionField ) != OGRERR_NONE ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Creation of field 'Description' failed" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !layer ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Creation of layer '" << layer_name << "' failed" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void*)layer;
|
||||
}
|
||||
|
||||
void* tgShapefile::CloseDatasource( void* ds_id )
|
||||
{
|
||||
OGRDataSource* datasource = ( OGRDataSource * )ds_id;
|
||||
OGRDataSource::DestroyDataSource( datasource );
|
||||
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
void tgShapefile::FromClipper( const ClipperLib::Polygons& subject, const std::string& datasource, const std::string& layer, const std::string& description )
|
||||
{
|
||||
void* ds_id = tgShapefile::OpenDatasource( datasource.c_str() );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenDatasource returned " << (unsigned long)ds_id);
|
||||
|
||||
OGRLayer* l_id = (OGRLayer *)tgShapefile::OpenLayer( ds_id, layer.c_str() );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenLayer returned " << (unsigned long)l_id);
|
||||
|
||||
OGRPolygon* polygon = new OGRPolygon();
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "subject has " << subject.size() << " contours ");
|
||||
|
||||
for ( unsigned int i = 0; i < subject.size(); i++ ) {
|
||||
ClipperLib::Polygon const& contour = subject[i];
|
||||
|
||||
if (contour.size() < 3) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Polygon with less than 3 points");
|
||||
} else {
|
||||
OGRLinearRing *ring = new OGRLinearRing();
|
||||
|
||||
// FIXME: Current we ignore the hole-flag and instead assume
|
||||
// that the first ring is not a hole and the rest
|
||||
// are holes
|
||||
for (unsigned int pt = 0; pt < contour.size(); pt++) {
|
||||
OGRPoint *point = new OGRPoint();
|
||||
SGGeod geod = SGGeod_FromClipper( contour[pt] );
|
||||
|
||||
point->setX( geod.getLongitudeDeg() );
|
||||
point->setY( geod.getLatitudeDeg() );
|
||||
point->setZ( 0.0 );
|
||||
|
||||
ring->addPoint( point );
|
||||
}
|
||||
|
||||
ring->closeRings();
|
||||
polygon->addRingDirectly( ring );
|
||||
}
|
||||
|
||||
OGRFeature* feature = new OGRFeature( l_id->GetLayerDefn() );
|
||||
|
||||
feature->SetField("ID", description.c_str());
|
||||
feature->SetGeometry(polygon);
|
||||
if( l_id->CreateFeature( feature ) != OGRERR_NONE )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile");
|
||||
}
|
||||
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
}
|
||||
}
|
||||
|
||||
void tgShapefile::FromPolygon( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description )
|
||||
{
|
||||
void* ds_id = tgShapefile::OpenDatasource( datasource.c_str() );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenDatasource returned " << (unsigned long)ds_id);
|
||||
|
||||
OGRLayer* l_id = (OGRLayer *)tgShapefile::OpenLayer( ds_id, layer.c_str() );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenLayer returned " << (unsigned long)l_id);
|
||||
|
||||
OGRPolygon* polygon = new OGRPolygon();
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "subject has " << subject.Contours() << " contours ");
|
||||
|
||||
for ( unsigned int i = 0; i < subject.Contours(); i++ ) {
|
||||
bool skip_ring=false;
|
||||
tgContour contour = subject.GetContour( i );
|
||||
|
||||
if (contour.GetSize() < 3) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Polygon with less than 3 points");
|
||||
skip_ring=true;
|
||||
}
|
||||
|
||||
// FIXME: Current we ignore the hole-flag and instead assume
|
||||
// that the first ring is not a hole and the rest
|
||||
// are holes
|
||||
OGRLinearRing *ring=new OGRLinearRing();
|
||||
for (unsigned int pt = 0; pt < contour.GetSize(); pt++) {
|
||||
OGRPoint *point=new OGRPoint();
|
||||
|
||||
point->setX( contour.GetNode(pt).getLongitudeDeg() );
|
||||
point->setY( contour.GetNode(pt).getLatitudeDeg() );
|
||||
point->setZ( 0.0 );
|
||||
ring->addPoint(point);
|
||||
}
|
||||
ring->closeRings();
|
||||
|
||||
if (!skip_ring) {
|
||||
polygon->addRingDirectly(ring);
|
||||
}
|
||||
|
||||
OGRFeature* feature = NULL;
|
||||
feature = new OGRFeature( l_id->GetLayerDefn() );
|
||||
feature->SetField("ID", description.c_str());
|
||||
feature->SetGeometry(polygon);
|
||||
if( l_id->CreateFeature( feature ) != OGRERR_NONE )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile");
|
||||
}
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
}
|
||||
|
||||
// close after each write
|
||||
ds_id = tgShapefile::CloseDatasource( ds_id );
|
||||
}
|
||||
|
||||
tgPolygon tgShapefile::ToPolygon( const void* subject )
|
||||
{
|
||||
const OGRPolygon* ogr_poly = (const OGRPolygon*)subject;
|
||||
OGRLinearRing const *ring = ogr_poly->getExteriorRing();
|
||||
|
||||
tgContour contour;
|
||||
tgPolygon result;
|
||||
|
||||
for (int i = 0; i < ring->getNumPoints(); i++) {
|
||||
contour.AddNode( SGGeod::fromDegM( ring->getX(i), ring->getY(i), ring->getZ(i)) );
|
||||
}
|
||||
contour.SetHole( false );
|
||||
result.AddContour( contour );
|
||||
|
||||
// then add the inner rings
|
||||
for ( int j = 0 ; j < ogr_poly->getNumInteriorRings(); j++ ) {
|
||||
ring = ogr_poly->getInteriorRing( j );
|
||||
contour.Erase();
|
||||
|
||||
for (int i = 0; i < ring->getNumPoints(); i++) {
|
||||
contour.AddNode( SGGeod::fromDegM( ring->getX(i), ring->getY(i), ring->getZ(i)) );
|
||||
}
|
||||
contour.SetHole( true );
|
||||
result.AddContour( contour );
|
||||
}
|
||||
result.SetTexMethod( TG_TEX_BY_GEODE );
|
||||
|
||||
return result;
|
||||
}
|
20
src/Lib/terragear/tg_shapefile.hxx
Normal file
20
src/Lib/terragear/tg_shapefile.hxx
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
#include "tg_polygon.hxx"
|
||||
#include "tg_contour.hxx"
|
||||
#include "clipper.hpp"
|
||||
|
||||
class tgShapefile
|
||||
{
|
||||
public:
|
||||
static void FromPolygon( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description );
|
||||
static tgPolygon ToPolygon( const void* subject );
|
||||
|
||||
static void FromClipper( const ClipperLib::Polygons& subject, const std::string& datasource, const std::string& layer, const std::string& description );
|
||||
|
||||
private:
|
||||
static bool initialized;
|
||||
|
||||
static void* OpenDatasource( const char* datasource_name );
|
||||
static void* OpenLayer( void* ds_id, const char* layer_name );
|
||||
static void* CloseDatasource( void* ds_id );
|
||||
};
|
|
@ -32,7 +32,7 @@
|
|||
#include <Array/array.hxx>
|
||||
|
||||
#include "TNT/jama_qr.h"
|
||||
#include "surface.hxx"
|
||||
#include "tg_surface.hxx"
|
||||
|
||||
// Final grid size for surface (in meters)
|
||||
const double coarse_grid = 300.0;
|
|
@ -28,7 +28,7 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "TNT/tnt_array2d.h"
|
||||
#include "polygon.hxx"
|
||||
#include "tg_polygon.hxx"
|
||||
|
||||
/***
|
||||
* A dirt simple matrix class for our convenience based on top of SGGeod
|
|
@ -3,7 +3,7 @@ add_executable(ogr-decode ogr-decode.cxx)
|
|||
|
||||
target_link_libraries(ogr-decode
|
||||
${GDAL_LIBRARY}
|
||||
Polygon
|
||||
terragear
|
||||
${SIMGEAR_CORE_LIBRARIES}
|
||||
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
|
||||
)
|
||||
|
|
|
@ -32,13 +32,15 @@
|
|||
#include <simgear/compiler.h>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGQueue.hxx>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <Include/version.h>
|
||||
#include <Polygon/polygon.hxx>
|
||||
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
#include <terragear/tg_chopper.hxx>
|
||||
#include <terragear/tg_shapefile.hxx>
|
||||
|
||||
/* stretch endpoints to reduce slivers in linear data ~.1 meters */
|
||||
#define EP_STRETCH (0.1)
|
||||
|
@ -195,7 +197,7 @@ void Decoder::processPolygon(OGRPolygon* poGeometry, const string& area_type )
|
|||
// bool preserve3D = ((poGeometry->getGeometryType()&wkb25DBit)==wkb25DBit);
|
||||
|
||||
// first add the outer ring
|
||||
tgPolygon shape = tgPolygon::FromOGR( poGeometry );
|
||||
tgPolygon shape = tgShapefile::ToPolygon( poGeometry );
|
||||
|
||||
if ( max_segment_length > 0 ) {
|
||||
shape = tgPolygon::SplitLongEdges( shape, max_segment_length );
|
||||
|
|
|
@ -7,7 +7,8 @@ endif(MSVC)
|
|||
|
||||
target_link_libraries(poly2ogr
|
||||
${GDAL_LIBRARY}
|
||||
Polygon ${GETOPT_LIB}
|
||||
terragear
|
||||
${GETOPT_LIB}
|
||||
${SIMGEAR_CORE_LIBRARIES}
|
||||
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
|
||||
)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <terragear/tg_polygon.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue