628 lines
14 KiB
C++
628 lines
14 KiB
C++
/**********************************************************************
|
|
*
|
|
* GEOS - Geometry Engine Open Source
|
|
* http://geos.osgeo.org
|
|
*
|
|
* Copyright (C) 2006 Refractions Research Inc.
|
|
*
|
|
* This is free software; you can redistribute and/or modify it under
|
|
* the terms of the GNU Lesser General Public Licence as published
|
|
* by the Free Software Foundation.
|
|
* See the COPYING file for more information.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include <geos/export.h>
|
|
#include <geos/constants.h> // for DoubleNotANumber
|
|
#include <set>
|
|
#include <unordered_set>
|
|
#include <stack>
|
|
#include <vector> // for typedefs
|
|
#include <string>
|
|
#include <limits>
|
|
#include <map>
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4251) // warning C4251: needs to have dll-interface to be used by clients of class
|
|
#endif
|
|
|
|
namespace geos {
|
|
namespace geom { // geos.geom
|
|
|
|
// Forward declarations
|
|
struct CoordinateLessThan;
|
|
class CoordinateXYZM;
|
|
class CoordinateXYM;
|
|
class Coordinate;
|
|
|
|
enum class CoordinateType : std::uint8_t {
|
|
XY,
|
|
XYZ,
|
|
XYZM,
|
|
XYM,
|
|
};
|
|
|
|
enum class Ordinate : std::uint8_t {
|
|
X,
|
|
Y,
|
|
Z,
|
|
M
|
|
};
|
|
|
|
GEOS_DLL std::ostream& operator<< (std::ostream&, const CoordinateType);
|
|
|
|
class GEOS_DLL CoordinateXY {
|
|
|
|
const static CoordinateXY _nullCoord;
|
|
|
|
protected:
|
|
constexpr const static double DEFAULT_X = 0.0;
|
|
constexpr const static double DEFAULT_Y = 0.0;
|
|
constexpr const static double DEFAULT_Z = DoubleNotANumber;
|
|
constexpr const static double DEFAULT_M = DoubleNotANumber;
|
|
|
|
public:
|
|
CoordinateXY()
|
|
: x(DEFAULT_X)
|
|
, y(DEFAULT_Y)
|
|
{}
|
|
|
|
CoordinateXY(double xNew, double yNew)
|
|
: x(xNew)
|
|
, y(yNew)
|
|
{}
|
|
|
|
template<Ordinate>
|
|
double get() const;
|
|
|
|
/// x-coordinate
|
|
double x;
|
|
|
|
/// y-coordinate
|
|
double y;
|
|
|
|
/// Equality operator for Coordinate. 2D only.
|
|
GEOS_DLL friend bool operator==(const CoordinateXY& a, const CoordinateXY& b)
|
|
{
|
|
return a.equals2D(b);
|
|
};
|
|
|
|
/// Inequality operator for Coordinate. 2D only.
|
|
GEOS_DLL friend bool operator!=(const CoordinateXY& a, const CoordinateXY& b)
|
|
{
|
|
return ! a.equals2D(b);
|
|
};
|
|
|
|
bool isValid() const
|
|
{
|
|
return std::isfinite(x) && std::isfinite(y);
|
|
};
|
|
|
|
bool equals2D(const CoordinateXY& other) const
|
|
{
|
|
if(x != other.x) {
|
|
return false;
|
|
}
|
|
if(y != other.y) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
bool equals2D(const CoordinateXY& other, double tolerance) const
|
|
{
|
|
if (std::abs(x - other.x) > tolerance) {
|
|
return false;
|
|
}
|
|
if (std::abs(y - other.y) > tolerance) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
/// 2D only
|
|
bool equals(const CoordinateXY& other) const
|
|
{
|
|
return equals2D(other);
|
|
};
|
|
|
|
/// TODO: deprecate this, move logic to CoordinateLessThan instead
|
|
inline int compareTo(const CoordinateXY& other) const
|
|
{
|
|
if(x < other.x) {
|
|
return -1;
|
|
}
|
|
if(x > other.x) {
|
|
return 1;
|
|
}
|
|
if(y < other.y) {
|
|
return -1;
|
|
}
|
|
if(y > other.y) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
static const CoordinateXY& getNull();
|
|
|
|
double distance(const CoordinateXY& p) const
|
|
{
|
|
double dx = x - p.x;
|
|
double dy = y - p.y;
|
|
return std::sqrt(dx * dx + dy * dy);
|
|
};
|
|
|
|
double distanceSquared(const CoordinateXY& p) const
|
|
{
|
|
double dx = x - p.x;
|
|
double dy = y - p.y;
|
|
return dx * dx + dy * dy;
|
|
};
|
|
|
|
bool isNull() const
|
|
{
|
|
return (std::isnan(x) && std::isnan(y));
|
|
};
|
|
|
|
void setNull()
|
|
{
|
|
x = DoubleNotANumber;
|
|
y = DoubleNotANumber;
|
|
};
|
|
|
|
struct GEOS_DLL HashCode
|
|
{
|
|
inline std::size_t operator()(const CoordinateXY& c) const
|
|
{
|
|
size_t h = std::hash<double>{}(c.x);
|
|
h ^= std::hash<double>{}(c.y) << 1;
|
|
// z ordinate ignored for consistency with operator==
|
|
return h;
|
|
};
|
|
};
|
|
|
|
using UnorderedSet = std::unordered_set<Coordinate, HashCode>;
|
|
|
|
/// Returns a string of the form <I>(x,y,z)</I> .
|
|
std::string toString() const;
|
|
};
|
|
|
|
/**
|
|
* \class Coordinate geom.h geos.h
|
|
*
|
|
* \brief
|
|
* Coordinate is the lightweight class used to store coordinates.
|
|
*
|
|
* It is distinct from Point, which is a subclass of Geometry.
|
|
* Unlike objects of type Point (which contain additional
|
|
* information such as an envelope, a precision model, and spatial
|
|
* reference system information), a Coordinate only contains
|
|
* ordinate values and accessor methods.
|
|
*
|
|
* Coordinate objects are two-dimensional points, with an additional
|
|
* z-ordinate. JTS does not support any operations on the z-ordinate except
|
|
* the basic accessor functions.
|
|
*
|
|
* Constructed coordinates will have a z-ordinate of DoubleNotANumber.
|
|
* The standard comparison functions will ignore the z-ordinate.
|
|
*
|
|
*/
|
|
// Define the following to make assignments and copy constructions
|
|
// NON-(will let profilers report usages)
|
|
//#define PROFILE_COORDINATE_COPIES 1
|
|
class GEOS_DLL Coordinate : public CoordinateXY {
|
|
|
|
private:
|
|
|
|
static const Coordinate _nullCoord;
|
|
|
|
public:
|
|
/// A set of const Coordinate pointers
|
|
typedef std::set<const Coordinate*, CoordinateLessThan> ConstSet;
|
|
typedef std::set<const CoordinateXY*, CoordinateLessThan> ConstXYSet;
|
|
|
|
/// A vector of const Coordinate pointers
|
|
typedef std::vector<const Coordinate*> ConstVect;
|
|
|
|
/// A stack of const Coordinate pointers
|
|
typedef std::stack<const Coordinate*> ConstStack;
|
|
|
|
/// A vector of Coordinate objects (real object, not pointers)
|
|
typedef std::vector<Coordinate> Vect;
|
|
|
|
/// A map of const Coordinate pointers to integers
|
|
typedef std::map<const CoordinateXY*, int, CoordinateLessThan> ConstIntMap;
|
|
|
|
/// z-coordinate
|
|
double z;
|
|
|
|
Coordinate()
|
|
: CoordinateXY()
|
|
, z(DEFAULT_Z)
|
|
{};
|
|
|
|
Coordinate(double xNew, double yNew, double zNew = DEFAULT_Z)
|
|
: CoordinateXY(xNew, yNew)
|
|
, z(zNew)
|
|
{};
|
|
|
|
explicit Coordinate(const CoordinateXY& other)
|
|
: CoordinateXY(other)
|
|
, z(DEFAULT_Z)
|
|
{};
|
|
|
|
template<Ordinate>
|
|
double get() const;
|
|
|
|
void setNull()
|
|
{
|
|
CoordinateXY::setNull();
|
|
z = DoubleNotANumber;
|
|
};
|
|
|
|
static const Coordinate& getNull();
|
|
|
|
bool isNull() const
|
|
{
|
|
return CoordinateXY::isNull() && std::isnan(z);
|
|
};
|
|
|
|
/// 3D comparison
|
|
bool equals3D(const Coordinate& other) const
|
|
{
|
|
return (x == other.x) && (y == other.y) &&
|
|
((z == other.z) || (std::isnan(z) && std::isnan(other.z)));
|
|
};
|
|
|
|
/// Returns a string of the form <I>(x,y,z)</I> .
|
|
std::string toString() const;
|
|
|
|
Coordinate& operator=(const CoordinateXY& other){
|
|
x = other.x;
|
|
y = other.y;
|
|
z = DEFAULT_Z;
|
|
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
|
|
class GEOS_DLL CoordinateXYM : public CoordinateXY {
|
|
private:
|
|
static const CoordinateXYM _nullCoord;
|
|
|
|
public:
|
|
CoordinateXYM() : CoordinateXYM(DEFAULT_X, DEFAULT_Y, DEFAULT_M) {}
|
|
|
|
explicit CoordinateXYM(const CoordinateXY& c)
|
|
: CoordinateXY(c)
|
|
, m(DEFAULT_M) {}
|
|
|
|
CoordinateXYM(double x_, double y_, double m_)
|
|
: CoordinateXY(x_, y_)
|
|
, m(m_) {}
|
|
|
|
double m;
|
|
|
|
template<Ordinate>
|
|
double get() const;
|
|
|
|
static const CoordinateXYM& getNull();
|
|
|
|
void setNull()
|
|
{
|
|
CoordinateXY::setNull();
|
|
m = DoubleNotANumber;
|
|
};
|
|
|
|
bool isNull() const
|
|
{
|
|
return CoordinateXY::isNull() && std::isnan(m);
|
|
}
|
|
bool equals3D(const CoordinateXYM& other) const {
|
|
return x == other.x && y == other.y && (m == other.m || (std::isnan(m) && std::isnan(other.m)));
|
|
}
|
|
|
|
CoordinateXYM& operator=(const CoordinateXYZM& other);
|
|
|
|
CoordinateXYM& operator=(const CoordinateXY& other) {
|
|
x = other.x;
|
|
y = other.y;
|
|
m = DEFAULT_M;
|
|
|
|
return *this;
|
|
}
|
|
|
|
std::string toString() const;
|
|
};
|
|
|
|
|
|
class GEOS_DLL CoordinateXYZM : public Coordinate {
|
|
private:
|
|
static const CoordinateXYZM _nullCoord;
|
|
|
|
public:
|
|
CoordinateXYZM() : CoordinateXYZM(DEFAULT_X, DEFAULT_Y, DEFAULT_Z, DEFAULT_M) {}
|
|
|
|
explicit CoordinateXYZM(const CoordinateXY& c)
|
|
: Coordinate(c)
|
|
, m(DEFAULT_M) {}
|
|
|
|
explicit CoordinateXYZM(const CoordinateXYM& c)
|
|
: Coordinate(c)
|
|
, m(c.m) {}
|
|
|
|
explicit CoordinateXYZM(const Coordinate& c)
|
|
: Coordinate(c)
|
|
, m(DEFAULT_M) {}
|
|
|
|
CoordinateXYZM(double x_, double y_, double z_, double m_)
|
|
: Coordinate(x_, y_, z_)
|
|
, m(m_) {}
|
|
|
|
double m;
|
|
|
|
template<Ordinate>
|
|
double get() const;
|
|
|
|
static const CoordinateXYZM& getNull();
|
|
|
|
void setNull()
|
|
{
|
|
Coordinate::setNull();
|
|
m = DoubleNotANumber;
|
|
};
|
|
|
|
|
|
bool isNull() const
|
|
{
|
|
return Coordinate::isNull() && std::isnan(m);
|
|
}
|
|
|
|
bool equals4D(const CoordinateXYZM& other) const {
|
|
return x == other.x && y == other.y &&
|
|
(z == other.z || (std::isnan(z) && std::isnan(other.z))) &&
|
|
(m == other.m || (std::isnan(m) && std::isnan(other.m)));
|
|
}
|
|
|
|
CoordinateXYZM& operator=(const CoordinateXY& other) {
|
|
x = other.x;
|
|
y = other.y;
|
|
z = DEFAULT_Z;
|
|
m = DEFAULT_M;
|
|
|
|
return *this;
|
|
}
|
|
|
|
CoordinateXYZM& operator=(const Coordinate& other) {
|
|
x = other.x;
|
|
y = other.y;
|
|
z = other.z;
|
|
m = DEFAULT_M;
|
|
|
|
return *this;
|
|
}
|
|
|
|
CoordinateXYZM& operator=(const CoordinateXYM& other) {
|
|
x = other.x;
|
|
y = other.y;
|
|
z = DEFAULT_Z;
|
|
m = other.m;
|
|
|
|
return *this;
|
|
}
|
|
|
|
std::string toString() const;
|
|
};
|
|
|
|
inline CoordinateXYM&
|
|
CoordinateXYM::operator=(const CoordinateXYZM& other) {
|
|
x = other.x;
|
|
y = other.y;
|
|
m = other.m;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
/// Strict weak ordering Functor for Coordinate
|
|
struct GEOS_DLL CoordinateLessThan {
|
|
|
|
bool operator()(const CoordinateXY* a, const CoordinateXY* b) const
|
|
{
|
|
if(a->compareTo(*b) < 0) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
bool operator()(const CoordinateXY& a, const CoordinateXY& b) const
|
|
{
|
|
if(a.compareTo(b) < 0) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
};
|
|
|
|
/// Strict weak ordering operator for Coordinate
|
|
inline bool operator<(const CoordinateXY& a, const CoordinateXY& b)
|
|
{
|
|
return CoordinateLessThan()(a, b);
|
|
}
|
|
|
|
|
|
// Generic accessors, XY
|
|
|
|
template<>
|
|
inline double CoordinateXY::get<Ordinate::X>() const
|
|
{
|
|
return x;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXY::get<Ordinate::Y>() const
|
|
{
|
|
return y;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXY::get<Ordinate::Z>() const
|
|
{
|
|
return DEFAULT_Z;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXY::get<Ordinate::M>() const
|
|
{
|
|
return DEFAULT_M;
|
|
}
|
|
|
|
// Generic accessors, XYZ
|
|
|
|
template<>
|
|
inline double Coordinate::get<Ordinate::X>() const
|
|
{
|
|
return x;
|
|
}
|
|
|
|
template<>
|
|
inline double Coordinate::get<Ordinate::Y>() const
|
|
{
|
|
return y;
|
|
}
|
|
|
|
template<>
|
|
inline double Coordinate::get<Ordinate::Z>() const
|
|
{
|
|
return z;
|
|
}
|
|
|
|
template<>
|
|
inline double Coordinate::get<Ordinate::M>() const
|
|
{
|
|
return DEFAULT_M;
|
|
}
|
|
|
|
// Generic accessors, XYM
|
|
|
|
template<>
|
|
inline double CoordinateXYM::get<Ordinate::X>() const
|
|
{
|
|
return x;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYM::get<Ordinate::Y>() const
|
|
{
|
|
return y;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYM::get<Ordinate::Z>() const
|
|
{
|
|
return DEFAULT_Z;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYM::get<Ordinate::M>() const
|
|
{
|
|
return m;
|
|
}
|
|
|
|
// Generic accessors, XYZM
|
|
|
|
template<>
|
|
inline double CoordinateXYZM::get<Ordinate::X>() const
|
|
{
|
|
return x;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYZM::get<Ordinate::Y>() const
|
|
{
|
|
return y;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYZM::get<Ordinate::Z>() const
|
|
{
|
|
return z;
|
|
}
|
|
|
|
template<>
|
|
inline double CoordinateXYZM::get<Ordinate::M>() const
|
|
{
|
|
return m;
|
|
}
|
|
|
|
GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateXY& c);
|
|
GEOS_DLL std::ostream& operator<< (std::ostream& os, const Coordinate& c);
|
|
GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateXYM& c);
|
|
GEOS_DLL std::ostream& operator<< (std::ostream& os, const CoordinateXYZM& c);
|
|
|
|
} // namespace geos.geom
|
|
} // namespace geos
|
|
|
|
// Add specializations of std::common_type for Coordinate types
|
|
namespace std {
|
|
template<> struct common_type<geos::geom::CoordinateXY, geos::geom::CoordinateXY> { using type = geos::geom::CoordinateXY; };
|
|
template<> struct common_type<geos::geom::CoordinateXY, geos::geom::Coordinate> { using type = geos::geom::Coordinate; };
|
|
template<> struct common_type<geos::geom::CoordinateXY, geos::geom::CoordinateXYM> { using type = geos::geom::CoordinateXYM; };
|
|
template<> struct common_type<geos::geom::CoordinateXY, geos::geom::CoordinateXYZM> { using type = geos::geom::CoordinateXYZM; };
|
|
|
|
template<> struct common_type<geos::geom::Coordinate, geos::geom::CoordinateXY> { using type = geos::geom::Coordinate; };
|
|
template<> struct common_type<geos::geom::Coordinate, geos::geom::Coordinate> { using type = geos::geom::Coordinate; };
|
|
template<> struct common_type<geos::geom::Coordinate, geos::geom::CoordinateXYM> { using type = geos::geom::CoordinateXYZM; };
|
|
template<> struct common_type<geos::geom::Coordinate, geos::geom::CoordinateXYZM> { using type = geos::geom::CoordinateXYZM; };
|
|
|
|
template<> struct common_type<geos::geom::CoordinateXYM, geos::geom::CoordinateXY> { using type = geos::geom::CoordinateXYM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYM, geos::geom::Coordinate> { using type = geos::geom::CoordinateXYZM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYM, geos::geom::CoordinateXYM> { using type = geos::geom::CoordinateXYM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYM, geos::geom::CoordinateXYZM> { using type = geos::geom::CoordinateXYZM; };
|
|
|
|
template<> struct common_type<geos::geom::CoordinateXYZM, geos::geom::CoordinateXY> { using type = geos::geom::CoordinateXYZM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYZM, geos::geom::Coordinate> { using type = geos::geom::CoordinateXYZM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYZM, geos::geom::CoordinateXYM> { using type = geos::geom::CoordinateXYZM; };
|
|
template<> struct common_type<geos::geom::CoordinateXYZM, geos::geom::CoordinateXYZM> { using type = geos::geom::CoordinateXYZM; };
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|