Added new independent classes for a bounding rectangle and a
multi-segment line, then pulled some local code out of tgvpf into util.[ch]xx so that it can be used by other modules.
This commit is contained in:
parent
6bd8a08f8b
commit
f30ffc0d1f
9 changed files with 571 additions and 194 deletions
src
|
@ -2,9 +2,12 @@ noinst_LIBRARIES = libGeometry.a
|
|||
|
||||
libGeometry_a_SOURCES = \
|
||||
contour_tree.cxx contour_tree.hxx \
|
||||
line.cxx line.hxx \
|
||||
poly_support.cxx poly_support.hxx \
|
||||
rectangle.cxx rectangle.hxx \
|
||||
trinodes.cxx trinodes.hxx \
|
||||
trisegs.cxx trisegs.hxx
|
||||
trisegs.cxx trisegs.hxx \
|
||||
util.cxx util.hxx
|
||||
|
||||
INCLUDES += \
|
||||
-I$(top_srcdir)/src \
|
||||
|
|
46
src/Lib/Geometry/line.cxx
Normal file
46
src/Lib/Geometry/line.cxx
Normal file
|
@ -0,0 +1,46 @@
|
|||
// line.cxx - a simple multi-segment line class.
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
|
||||
#include "line.hxx"
|
||||
|
||||
Line::Line ()
|
||||
{
|
||||
}
|
||||
|
||||
Line::Line (const Line &l)
|
||||
{
|
||||
}
|
||||
|
||||
Line::~Line ()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
Line::getPointCount () const
|
||||
{
|
||||
return _points.size();
|
||||
}
|
||||
|
||||
const Point3D &
|
||||
Line::getPoint (int index) const
|
||||
{
|
||||
return _points[index];
|
||||
}
|
||||
|
||||
Point3D &
|
||||
Line::getPoint (int index)
|
||||
{
|
||||
return _points[index];
|
||||
}
|
||||
|
||||
void
|
||||
Line::addPoint (const Point3D &point)
|
||||
{
|
||||
_points.push_back(point);
|
||||
}
|
||||
|
||||
// end of line.cxx
|
83
src/Lib/Geometry/line.hxx
Normal file
83
src/Lib/Geometry/line.hxx
Normal file
|
@ -0,0 +1,83 @@
|
|||
// line.hxx - a simple multi-segment line class.
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#ifndef __LINE_HXX
|
||||
#define __LINE_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include "rectangle.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* A simple multi-segment line class.
|
||||
*
|
||||
* A line segment is a growable list of points. I will add more
|
||||
* functionality if or when it is needed.
|
||||
*/
|
||||
class Line
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a new line with no points.
|
||||
*/
|
||||
Line ();
|
||||
|
||||
/**
|
||||
* Copy an existing line.
|
||||
*
|
||||
* @param l The line to copy.
|
||||
*/
|
||||
Line (const Line &l);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Line ();
|
||||
|
||||
/**
|
||||
* Get the number of points currently in the line.
|
||||
*
|
||||
* @return The point count.
|
||||
*/
|
||||
virtual int getPointCount () const;
|
||||
|
||||
/**
|
||||
* Get a point in the line (const).
|
||||
*
|
||||
* @param index The index of the point, zero-based.
|
||||
* @return The point at the index specified.
|
||||
*/
|
||||
virtual const Point3D &getPoint (int index) const;
|
||||
|
||||
/**
|
||||
* Get a point in the line (non-const).
|
||||
*
|
||||
* @param index The index of the point, zero-based.
|
||||
* @return The point at the index specified.
|
||||
*/
|
||||
virtual Point3D &getPoint (int index);
|
||||
|
||||
/**
|
||||
* Add a new point to the end of the line.
|
||||
*
|
||||
* @param point The point to add.
|
||||
*/
|
||||
virtual void addPoint (const Point3D &point);
|
||||
|
||||
private:
|
||||
vector<Point3D> _points;
|
||||
};
|
||||
|
||||
#endif // __LINE_HXX
|
58
src/Lib/Geometry/rectangle.cxx
Normal file
58
src/Lib/Geometry/rectangle.cxx
Normal file
|
@ -0,0 +1,58 @@
|
|||
// rectangle.cxx - a simple rectangle class (for bounds, etc.)
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#include "rectangle.hxx"
|
||||
|
||||
Rectangle::Rectangle ()
|
||||
{
|
||||
}
|
||||
|
||||
Rectangle::Rectangle (const Rectangle &r)
|
||||
: _min(r.getMin()),
|
||||
_max(r.getMax())
|
||||
{
|
||||
}
|
||||
|
||||
Rectangle::~Rectangle ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Rectangle::setMin (const Point3D &p)
|
||||
{
|
||||
_min = p;
|
||||
}
|
||||
|
||||
void
|
||||
Rectangle::setMax (const Point3D &p)
|
||||
{
|
||||
_max = p;
|
||||
}
|
||||
|
||||
void
|
||||
Rectangle::sanify ()
|
||||
{
|
||||
double tmp;
|
||||
if (_min.x() > _max.x()) {
|
||||
tmp = _min.x();
|
||||
_min.setx(_max.x());
|
||||
_max.setx(tmp);
|
||||
}
|
||||
if (_min.y() > _max.y()) {
|
||||
tmp = _min.y();
|
||||
_min.sety(_max.y());
|
||||
_max.sety(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Rectangle::isInside (const Point3D &p) const
|
||||
{
|
||||
return ((p.x() >= _min.x() && p.x() <= _max.x()) &&
|
||||
(p.y() >= _min.y() && p.y() <= _max.y()));
|
||||
}
|
||||
|
||||
// end of rectangle.cxx
|
98
src/Lib/Geometry/rectangle.hxx
Normal file
98
src/Lib/Geometry/rectangle.hxx
Normal file
|
@ -0,0 +1,98 @@
|
|||
// rectangle.hxx - a simple rectangle class (for bounds, etc.)
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#ifndef __RECTANGLE_HXX
|
||||
#define __RECTANGLE_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
|
||||
/**
|
||||
* A simple rectangle class for bounding rectanglees.
|
||||
*
|
||||
* The class defines a rectangle in by the vertices of its minimum and
|
||||
* maximum corners, ignoring any z coordinates. There are methods to
|
||||
* sanify the rectangle (to make certain that each point is correct)
|
||||
* and to test whether another point lies inside it.
|
||||
*/
|
||||
class Rectangle
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a new empty rectangle with both points at 0,0.
|
||||
*/
|
||||
Rectangle ();
|
||||
|
||||
/**
|
||||
* Copy an existing rectangle.
|
||||
*
|
||||
* @param r The rectangle to copy.
|
||||
*/
|
||||
Rectangle (const Rectangle &r);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Rectangle ();
|
||||
|
||||
/**
|
||||
* Get the minimum (top left) corner of the rectangle.
|
||||
*
|
||||
* @return The top-left vertex.
|
||||
*/
|
||||
virtual const Point3D &getMin () const { return _min; }
|
||||
|
||||
/**
|
||||
* Get the maximum (bottom right) corner of the rectangle.
|
||||
*
|
||||
* @return The bottom-right vertex.
|
||||
*/
|
||||
virtual const Point3D &getMax () const { return _max; }
|
||||
|
||||
/**
|
||||
* Set the minimum (top-left) corner of the rectangle.
|
||||
*
|
||||
* @param p The top-left vertex.
|
||||
*/
|
||||
virtual void setMin (const Point3D &p);
|
||||
|
||||
/**
|
||||
* Set the maximum (bottom-right) corner of the rectangle.
|
||||
*
|
||||
* @param p The bottom-right vertex.
|
||||
*/
|
||||
virtual void setMax (const Point3D &p);
|
||||
|
||||
/**
|
||||
* Make the rectangle sane.
|
||||
*
|
||||
* Ensure that the min vertex is less than the max vertex.
|
||||
*/
|
||||
virtual void sanify ();
|
||||
|
||||
/**
|
||||
* Test whether a point lies inside the rectangle.
|
||||
*
|
||||
* The z-coordinates are ignored.
|
||||
*
|
||||
* @param p The point to test.
|
||||
* @return true if the point is inside or on the boundary of the
|
||||
* rectangle, false if it is outside.
|
||||
*/
|
||||
virtual bool isInside (const Point3D &p) const;
|
||||
|
||||
private:
|
||||
Point3D _min;
|
||||
Point3D _max;
|
||||
};
|
||||
|
||||
#endif // __RECTANGLE_HXX
|
147
src/Lib/Geometry/util.cxx
Normal file
147
src/Lib/Geometry/util.cxx
Normal file
|
@ -0,0 +1,147 @@
|
|||
// util.cxx - a collection of simple geometry utility functions.
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#include "util.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
|
||||
|
||||
bool
|
||||
getIntersection (const Point3D &p0, const Point3D &p1,
|
||||
const Point3D &p2, const Point3D &p3,
|
||||
Point3D &intersection)
|
||||
{
|
||||
double u_num =
|
||||
((p3.x()-p2.x())*(p0.y()-p2.y()))-((p3.y()-p2.y())*(p0.x()-p2.x()));
|
||||
double u_den =
|
||||
((p3.y()-p2.y())*(p1.x()-p0.x()))-((p3.x()-p2.x())*(p1.y()-p0.y()));
|
||||
|
||||
if (u_den == 0) {
|
||||
if (u_num == 0)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: coincident lines");
|
||||
else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: parallel lines");
|
||||
return false;
|
||||
} else {
|
||||
double u = u_num/u_den;
|
||||
intersection = Point3D((p0.x()+u*(p1.x()-p0.x())),
|
||||
(p0.y()+u*(p1.y()-p0.y())),
|
||||
0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a point.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*/
|
||||
void
|
||||
makePolygon (const Point3D &p, int width, FGPolygon &polygon)
|
||||
{
|
||||
double x, y, az;
|
||||
double lon = p.x();
|
||||
double lat = p.y();
|
||||
|
||||
polygon.erase();
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 90, width/2, &y, &x, &az);
|
||||
double dlon = x - lon;
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 0, width/2, &y, &x, &az);
|
||||
double dlat = y - lat;
|
||||
|
||||
polygon.add_node(0, Point3D(lon - dlon, lat - dlat, 0));
|
||||
polygon.add_node(0, Point3D(lon + dlon, lat - dlat, 0));
|
||||
polygon.add_node(0, Point3D(lon + dlon, lat + dlat, 0));
|
||||
polygon.add_node(0, Point3D(lon - dlon, lat + dlat, 0));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
makePolygon (const Line &line, int width, FGPolygon &polygon)
|
||||
{
|
||||
vector<FGPolygon> segment_list;
|
||||
|
||||
int nPoints = line.getPointCount();
|
||||
int i;
|
||||
for (i = 0; i < nPoints - 1; i++) {
|
||||
const Point3D p1 = line.getPoint(i);
|
||||
const Point3D p2 = line.getPoint(i+1);
|
||||
|
||||
double angle1, angle2, dist, x, y, az;
|
||||
|
||||
geo_inverse_wgs_84(0, p1.y(), p1.x(), p2.y(), p2.x(), &angle1, &angle2, &dist);
|
||||
polygon.erase();
|
||||
|
||||
// Wind each rectangle counterclockwise
|
||||
|
||||
// Corner 1
|
||||
geo_direct_wgs_84(0, p1.y(), p1.x(), CLAMP_ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
polygon.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 2
|
||||
geo_direct_wgs_84(0, p2.y(), p2.x(), CLAMP_ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
polygon.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 3
|
||||
geo_direct_wgs_84(0, p2.y(), p2.x(), CLAMP_ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
polygon.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 4
|
||||
geo_direct_wgs_84(0, p1.y(), p1.x(), CLAMP_ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
polygon.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Save this rectangle
|
||||
segment_list.push_back(polygon);
|
||||
}
|
||||
|
||||
// Build one big polygon out of all the rectangles by intersecting
|
||||
// the lines running through the bottom and top sides
|
||||
|
||||
polygon.erase();
|
||||
|
||||
// Connect the bottom part.
|
||||
int nSegments = segment_list.size();
|
||||
Point3D intersection;
|
||||
polygon.add_node(0, segment_list[0].get_pt(0, 0));
|
||||
for (i = 0; i < nSegments - 1; i++) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 0),
|
||||
segment_list[i].get_pt(0, 1),
|
||||
segment_list[i+1].get_pt(0, 0),
|
||||
segment_list[i+1].get_pt(0, 1),
|
||||
intersection))
|
||||
polygon.add_node(0, intersection);
|
||||
else
|
||||
polygon.add_node(0, segment_list[i].get_pt(0, 1));
|
||||
}
|
||||
polygon.add_node(0, segment_list[nSegments-1].get_pt(0, 1));
|
||||
|
||||
// Connect the top part
|
||||
polygon.add_node(0, segment_list[nSegments-1].get_pt(0, 2));
|
||||
for (i = nSegments - 1; i > 0; i--) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 2),
|
||||
segment_list[i].get_pt(0, 3),
|
||||
segment_list[i-1].get_pt(0, 2),
|
||||
segment_list[i-1].get_pt(0, 3),
|
||||
intersection))
|
||||
polygon.add_node(0, intersection);
|
||||
else
|
||||
polygon.add_node(0, segment_list[i].get_pt(0, 3));
|
||||
}
|
||||
polygon.add_node(0, segment_list[0].get_pt(0, 3));
|
||||
}
|
||||
|
||||
|
||||
// end of util.cxx
|
87
src/Lib/Geometry/util.hxx
Normal file
87
src/Lib/Geometry/util.hxx
Normal file
|
@ -0,0 +1,87 @@
|
|||
// util.hxx - a collection of simple WGS84 utility functions.
|
||||
//
|
||||
// Started by David Megginson, July 2002
|
||||
//
|
||||
// This file is in the Public Domain and comes with NO WARRANTY OF ANY KIND.
|
||||
|
||||
#ifndef __UTIL_HXX
|
||||
#define __UTIL_HXX 1
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
|
||||
#include "line.hxx"
|
||||
|
||||
|
||||
/**
|
||||
* Inline function to clamp an angle between 0 and 360 degrees.
|
||||
*
|
||||
* @param a The angle to clamp, in degrees.
|
||||
* @return The clamped angle.
|
||||
*/
|
||||
inline double
|
||||
CLAMP_ANGLE (double a)
|
||||
{
|
||||
while (a < 0.0)
|
||||
a += 360.0;
|
||||
while (a >= 360.0)
|
||||
a -= 360.0;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two line segments.
|
||||
*
|
||||
* @param p0 First point on the first segment.
|
||||
* @param p1 A second point on the second segment.
|
||||
* @param p2 First point on the second segment.
|
||||
* @param p3 A second point on the second segment.
|
||||
* @param intersection A variable to hold the calculated intersection.
|
||||
* @return true if there was an intersection, false if the segments.
|
||||
* are parallel or coincident.
|
||||
*/
|
||||
bool getIntersection (const Point3D &p0, const Point3D &p1,
|
||||
const Point3D &p2, const Point3D &p3,
|
||||
Point3D &intersection);
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a point.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*
|
||||
* @param p The point at the centre of the new polygon.
|
||||
* @param width The width in standard units (meters for FlightGear).
|
||||
* @param polygon The object that will hold the new polygon.
|
||||
*/
|
||||
void makePolygon (const Point3D &p, int width, FGPolygon &polygon);
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a line.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*
|
||||
* @param line The multi-segment line inside the new polygon.
|
||||
* @param width The width in standard units (meters for FlightGear).
|
||||
* @param polygon The object that will hold the new polygon.
|
||||
*/
|
||||
void makePolygon (const Line &line, int width, FGPolygon &polygon);
|
||||
|
||||
|
||||
#endif // __UTIL_HXX
|
|
@ -3,6 +3,7 @@ bin_PROGRAMS = tgvpf
|
|||
tgvpf_SOURCES = tgvpf.cxx
|
||||
|
||||
tgvpf_LDADD = \
|
||||
$(top_builddir)/src/Lib/Geometry/libGeometry.a \
|
||||
$(top_builddir)/src/Lib/Polygon/libPolygon.a \
|
||||
$(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \
|
||||
$(top_builddir)/src/Lib/vpf/libvpf.a \
|
||||
|
|
|
@ -44,6 +44,8 @@ SG_USING_STD(cout);
|
|||
SG_USING_STD(string);
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include <Geometry/line.hxx>
|
||||
#include <Geometry/util.hxx>
|
||||
#include <Polygon/index.hxx>
|
||||
#include <Polygon/names.hxx>
|
||||
#include <Polygon/polygon.hxx>
|
||||
|
@ -65,11 +67,13 @@ static const char * progname;
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Utility stuff.
|
||||
// VPF conversion code.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static inline ostream &
|
||||
/**
|
||||
* Print out a VPF bounding rectangle.
|
||||
*/
|
||||
static ostream &
|
||||
operator<< (ostream &output, const VpfRectangle &rect)
|
||||
{
|
||||
output << rect.minX << ','
|
||||
|
@ -79,54 +83,53 @@ operator<< (ostream &output, const VpfRectangle &rect)
|
|||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inline function to clamp an angle between 0 and 360 degrees.
|
||||
* Convert a VPF point to a regular TerraGear point.
|
||||
*/
|
||||
static inline double
|
||||
ANGLE (double a)
|
||||
static inline const Point3D
|
||||
vpf2tg (const VpfPoint &p)
|
||||
{
|
||||
while (a < 0.0)
|
||||
a += 360.0;
|
||||
while (a >= 360.0)
|
||||
a -= 360.0;
|
||||
return a;
|
||||
return Point3D(p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two lines.
|
||||
*
|
||||
* @param p0 First point on the first line.
|
||||
* @param p1 A second point on the first line.
|
||||
* @param p2 First point on the second line.
|
||||
* @param p3 A second point on the second line.
|
||||
* @param intersection A variable to hold the calculated intersection.
|
||||
* @return true if there was an intersection, false if the lines
|
||||
* are parallel or coincident.
|
||||
* Convert a VPF line to a regular TerraGear line.
|
||||
*/
|
||||
static bool
|
||||
getIntersection (const Point3D &p0, const Point3D &p1,
|
||||
const Point3D &p2, const Point3D &p3,
|
||||
Point3D &intersection)
|
||||
static const Line
|
||||
vpf2tg (const VpfLine &l)
|
||||
{
|
||||
double u_num =
|
||||
((p3.x()-p2.x())*(p0.y()-p2.y()))-((p3.y()-p2.y())*(p0.x()-p2.x()));
|
||||
double u_den =
|
||||
((p3.y()-p2.y())*(p1.x()-p0.x()))-((p3.x()-p2.x())*(p1.y()-p0.y()));
|
||||
Line result;
|
||||
int nPoints = l.getPointCount();
|
||||
for (int i = 0; i < nPoints; i++)
|
||||
result.addPoint(vpf2tg(l.getPoint(i)));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (u_den == 0) {
|
||||
if (u_num == 0)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: coincident lines");
|
||||
else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: parallel lines");
|
||||
return false;
|
||||
} else {
|
||||
double u = u_num/u_den;
|
||||
intersection = Point3D((p0.x()+u*(p1.x()-p0.x())),
|
||||
(p0.y()+u*(p1.y()-p0.y())),
|
||||
0);
|
||||
return true;
|
||||
|
||||
/**
|
||||
* Convert a VPF polygon to a TerraGear polygon.
|
||||
*/
|
||||
static const FGPolygon
|
||||
vpf2tg (const VpfPolygon &polygon)
|
||||
{
|
||||
FGPolygon shape;
|
||||
|
||||
shape.erase();
|
||||
int nContours = polygon.getContourCount();
|
||||
int contour_num = 0;
|
||||
for (int i = 0; i < nContours; i++) {
|
||||
const VpfContour contour = polygon.getContour(i);
|
||||
int nPoints = contour.getPointCount();
|
||||
for (int j = 0; j < nPoints; j++) {
|
||||
const VpfPoint p = contour.getPoint(j);
|
||||
shape.add_node(contour_num, Point3D(p.x, p.y, p.z));
|
||||
}
|
||||
shape.set_hole_flag(contour_num, (i > 0));
|
||||
contour_num++;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,155 +178,6 @@ checkAttribute (const VpfFeature &feature, int index, const Attribute &att)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a point.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfPoint &p, int width)
|
||||
{
|
||||
FGPolygon result;
|
||||
|
||||
double x, y, az;
|
||||
double lon = p.x;
|
||||
double lat = p.y;
|
||||
|
||||
result.erase();
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 90, width/2, &y, &x, &az);
|
||||
double dlon = x - lon;
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 0, width/2, &y, &x, &az);
|
||||
double dlat = y - lat;
|
||||
|
||||
result.add_node(0, Point3D(lon - dlon, lat - dlat, 0));
|
||||
result.add_node(0, Point3D(lon + dlon, lat - dlat, 0));
|
||||
result.add_node(0, Point3D(lon + dlon, lat + dlat, 0));
|
||||
result.add_node(0, Point3D(lon - dlon, lat + dlat, 0));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a line.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfLine &line, int width)
|
||||
{
|
||||
FGPolygon shape;
|
||||
|
||||
vector<FGPolygon> segment_list;
|
||||
|
||||
int nPoints = line.getPointCount();
|
||||
int i;
|
||||
for (i = 0; i < nPoints - 1; i++) {
|
||||
const VpfPoint p1 = line.getPoint(i);
|
||||
const VpfPoint p2 = line.getPoint(i+1);
|
||||
|
||||
double angle1, angle2, dist, x, y, az;
|
||||
|
||||
geo_inverse_wgs_84(0, p1.y, p1.x, p2.y, p2.x, &angle1, &angle2, &dist);
|
||||
shape.erase();
|
||||
|
||||
// Wind each rectangle counterclockwise
|
||||
|
||||
// Corner 1
|
||||
geo_direct_wgs_84(0, p1.y, p1.x, ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 2
|
||||
geo_direct_wgs_84(0, p2.y, p2.x, ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 3
|
||||
geo_direct_wgs_84(0, p2.y, p2.x, ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 4
|
||||
geo_direct_wgs_84(0, p1.y, p1.x, ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Save this rectangle
|
||||
segment_list.push_back(shape);
|
||||
}
|
||||
|
||||
// Build one big polygon out of all the rectangles by intersecting
|
||||
// the lines running through the bottom and top sides
|
||||
|
||||
shape.erase();
|
||||
|
||||
// Connect the bottom part.
|
||||
int nSegments = segment_list.size();
|
||||
Point3D intersection;
|
||||
shape.add_node(0, segment_list[0].get_pt(0, 0));
|
||||
for (i = 0; i < nSegments - 1; i++) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 0),
|
||||
segment_list[i].get_pt(0, 1),
|
||||
segment_list[i+1].get_pt(0, 0),
|
||||
segment_list[i+1].get_pt(0, 1),
|
||||
intersection))
|
||||
shape.add_node(0, intersection);
|
||||
else
|
||||
shape.add_node(0, segment_list[i].get_pt(0, 1));
|
||||
}
|
||||
shape.add_node(0, segment_list[nSegments-1].get_pt(0, 1));
|
||||
|
||||
// Connect the top part
|
||||
shape.add_node(0, segment_list[nSegments-1].get_pt(0, 2));
|
||||
for (i = nSegments - 1; i > 0; i--) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 2),
|
||||
segment_list[i].get_pt(0, 3),
|
||||
segment_list[i-1].get_pt(0, 2),
|
||||
segment_list[i-1].get_pt(0, 3),
|
||||
intersection))
|
||||
shape.add_node(0, intersection);
|
||||
else
|
||||
shape.add_node(0, segment_list[i].get_pt(0, 3));
|
||||
}
|
||||
shape.add_node(0, segment_list[0].get_pt(0, 3));
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Import all polygons.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfPolygon &polygon)
|
||||
{
|
||||
FGPolygon shape;
|
||||
|
||||
shape.erase();
|
||||
int nContours = polygon.getContourCount();
|
||||
int contour_num = 0;
|
||||
for (int i = 0; i < nContours; i++) {
|
||||
const VpfContour contour = polygon.getContour(i);
|
||||
int nPoints = contour.getPointCount();
|
||||
for (int j = 0; j < nPoints; j++) {
|
||||
const VpfPoint p = contour.getPoint(j);
|
||||
shape.add_node(contour_num, Point3D(p.x, p.y, p.z));
|
||||
}
|
||||
shape.set_hole_flag(contour_num, (i > 0));
|
||||
contour_num++;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Main program.
|
||||
|
@ -657,28 +511,28 @@ main (int argc, const char **argv)
|
|||
const VpfPoint p = feature.getPoint(i);
|
||||
if (!inside(p, bounds))
|
||||
continue;
|
||||
shape = makePolygon(p, (width == -1 ? 500 : width));
|
||||
makePolygon(vpf2tg(p), (width == -1 ? 500 : width), shape);
|
||||
break;
|
||||
}
|
||||
case VpfFeature::LINE: {
|
||||
const VpfLine line = feature.getLine(i);
|
||||
if (!overlap(line.getBoundingRectangle(), bounds))
|
||||
continue;
|
||||
shape = makePolygon(line, (width == -1 ? 50 : width));
|
||||
makePolygon(vpf2tg(line), (width == -1 ? 50 : width), shape);
|
||||
break;
|
||||
}
|
||||
case VpfFeature::POLYGON: {
|
||||
const VpfPolygon polygon = feature.getPolygon(i);
|
||||
if (!overlap(polygon.getBoundingRectangle(), bounds))
|
||||
continue;
|
||||
shape = makePolygon(polygon);
|
||||
shape = vpf2tg(polygon);
|
||||
break;
|
||||
}
|
||||
case VpfFeature::LABEL: {
|
||||
const VpfPoint p = feature.getLabel(i).getPoint();
|
||||
if (!inside(p, bounds))
|
||||
continue;
|
||||
shape = makePolygon(p, (width == -1 ? 500 : width));
|
||||
makePolygon(vpf2tg(p), (width == -1 ? 500 : width), shape);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Add table
Reference in a new issue