Skip to content

Commit

Permalink
let Geography store variant
Browse files Browse the repository at this point in the history
  • Loading branch information
jievince committed Oct 11, 2021
1 parent 6072b41 commit 53b8b2b
Show file tree
Hide file tree
Showing 36 changed files with 1,101 additions and 542 deletions.
8 changes: 8 additions & 0 deletions src/common/datatypes/CommonCpp2Ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ struct Map;
struct Set;
struct List;
struct DataSet;
struct Coordinate;
struct Point;
struct LineString;
struct Polygon;
struct Geography;
} // namespace nebula

Expand All @@ -44,6 +48,10 @@ SPECIALIZE_CPP2OPS(nebula::Map);
SPECIALIZE_CPP2OPS(nebula::Set);
SPECIALIZE_CPP2OPS(nebula::List);
SPECIALIZE_CPP2OPS(nebula::DataSet);
SPECIALIZE_CPP2OPS(nebula::Coordinate);
SPECIALIZE_CPP2OPS(nebula::Point);
SPECIALIZE_CPP2OPS(nebula::LineString);
SPECIALIZE_CPP2OPS(nebula::Polygon);
SPECIALIZE_CPP2OPS(nebula::Geography);

} // namespace apache::thrift
Expand Down
4 changes: 4 additions & 0 deletions src/common/datatypes/DataSetOps-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,13 @@ _readField_rows : {
}

if (proto->kUsesFieldNames()) {
LOG(INFO) << "Dataset: proto->kUsesFieldNames()";
detail::TccStructTraits<nebula::DataSet>::translateFieldName(
readState.fieldName(), readState.fieldId, readState.fieldType);
} else {
LOG(INFO) << "Dataset:: !proto->kUsesFieldNames()";
}
LOG(INFO) << "jie, dataset, readState.fieldId: " << readState.fieldId;

switch (readState.fieldId) {
case 1: {
Expand Down
258 changes: 193 additions & 65 deletions src/common/datatypes/Geography.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,113 +19,241 @@

namespace nebula {

Geography::Geography(const Geometry& geom) { wkb = WKBWriter().write(geom); }
void Coordinate::normalize() {
// Reduce the x(longitude) to the range [-180, 180] degrees
x = std::remainder(x, 360.0);

StatusOr<Geography> Geography::fromWKT(const std::string& wkt) {
auto geomRet = WKTReader().read(wkt);
NG_RETURN_IF_ERROR(geomRet);
auto geom = geomRet.value();
auto bytes = WKBWriter().write(geom);
return Geography(bytes);
// Reduce the y(latitude) to the range [-90, 90] degrees
double tmp = remainder(y, 360.0);
if (tmp > 90.0) {
y = 180.0 - tmp;
}
if (tmp < -90.0) {
y = -180.0 - tmp;
}
}

GeoShape Geography::shape() const {
ByteOrderDataInStream dis(wkb);
auto byteOrderValRet = dis.readUint8();
if (!byteOrderValRet.ok()) {
return GeoShape::UNKNOWN;
bool Coordinate::isValid() const { return std::abs(x) <= 180.0 && std::abs(y) <= 90.0; }

void Point::normalize() {}

bool Point::isValid() const { return coord.isValid(); }

void LineString::normalize() { GeoUtils::removeAdjacentDuplicateCoordinates(coordList); }

bool LineString::isValid() const {
// LineString must have at least 2 coordinates;
if (coordList.size() < 2) {
return false;
}
ByteOrder byteOrder = static_cast<ByteOrder>(byteOrderValRet.value());
dis.setByteOrder(byteOrder);
auto shapeTypeValRet = dis.readUint32();
if (!shapeTypeValRet.ok()) {
return GeoShape::UNKNOWN;
auto s2Region = GeoUtils::s2RegionFromGeography(*this);
return static_cast<S2Polyline*>(s2Region.get())->IsValid();
}

void Polygon::normalize() {
for (auto& coordList : coordListList) {
GeoUtils::removeAdjacentDuplicateCoordinates(coordList);
}
return static_cast<GeoShape>(shapeTypeValRet.value());
}

bool Geography::isValid() const {
auto geom = this->asGeometry();
if (!geom) {
return false;
bool Polygon::isValid() const {
for (const auto& coordList : coordListList) {
// Polygon's LinearRing must have at least 4 coordinates
if (coordList.size() < 4) {
return false;
}
// Polygon's LinearRing must be closed
if (coordList.front() != coordList.back()) {
return false;
}
}
auto s2Region = GeoUtils::s2RegionFromGeography(*this);
return static_cast<S2Polygon*>(s2Region.get())->IsValid();
}

if (!geom->isValid()) {
return false;
StatusOr<Geography> Geography::fromWKT(const std::string& wkt,
bool needNormalize,
bool verifyValidity) {
auto geogRet = WKTReader().read(wkt);
if (!geogRet.ok()) {
return geogRet;
}
auto geog = std::move(geogRet.value());
if (needNormalize) {
geog.normalize();
}
if (verifyValidity) {
if (!geog.isValid()) {
return Status::Error("Failed to parse an valid Geography instance from the wkt `%s'",
wkt.c_str());
}
}

return geog;
}

GeoShape Geography::shape() const {
switch (geo_.index()) {
case 0:
return GeoShape::POINT;
case 1:
return GeoShape::LINESTRING;
case 2:
return GeoShape::POLYGON;
default: // May never reaches here, because the default constructor of the variant geo_ will
// hold the value-initialized value of the first alternative(Point).
return GeoShape::UNKNOWN;
}
}

const Point& Geography::point() const {
CHECK(std::holds_alternative<Point>(geo_));
return std::get<Point>(geo_);
}

const LineString& Geography::lineString() const {
CHECK(std::holds_alternative<LineString>(geo_));
return std::get<LineString>(geo_);
}

const Polygon& Geography::polygon() const {
CHECK(std::holds_alternative<Polygon>(geo_));
return std::get<Polygon>(geo_);
}

Point& Geography::mutablePoint() {
CHECK(std::holds_alternative<Point>(geo_));
return std::get<Point>(geo_);
}

LineString& Geography::mutableLineString() {
CHECK(std::holds_alternative<LineString>(geo_));
return std::get<LineString>(geo_);
}

Polygon& Geography::mutablePolygon() {
CHECK(std::holds_alternative<Polygon>(geo_));
return std::get<Polygon>(geo_);
}

void Geography::normalize() {
switch (shape()) {
case GeoShape::POINT: {
const auto& point = geom->point();
return std::abs(point.coord.x) <= 180.0 && std::abs(point.coord.y) <= 90.0;
auto& point = mutablePoint();
point.normalize();
return;
}
case GeoShape::LINESTRING: {
auto s2Region = GeoUtils::s2RegionFromGeomtry(*geom);
return static_cast<S2Polyline*>(s2Region.get())->IsValid();
auto& line = mutableLineString();
line.normalize();
return;
}
case GeoShape::POLYGON: {
auto s2Region = GeoUtils::s2RegionFromGeomtry(*geom);
return static_cast<S2Polygon*>(s2Region.get())->IsValid();
auto& polygon = mutablePolygon();
polygon.normalize();
return;
}
case GeoShape::UNKNOWN:
default: {
LOG(ERROR)
<< "Geography shapes other than Point/LineString/Polygon are not currently supported";
return false;
return;
}
}

return false;
}

std::unique_ptr<std::string> Geography::asWKT() const {
auto geomRet = WKBReader().read(wkb);
if (!geomRet.ok()) {
LOG(ERROR) << geomRet.status();
return nullptr;
bool Geography::isValid() const {
switch (shape()) {
case GeoShape::POINT: {
const auto& point = this->point();
return point.isValid();
}
case GeoShape::LINESTRING: {
const auto& line = this->lineString();
return line.isValid();
}
case GeoShape::POLYGON: {
const auto& polygon = this->polygon();
return polygon.isValid();
}
case GeoShape::UNKNOWN:
default: {
LOG(ERROR)
<< "Geography shapes other than Point/LineString/Polygon are not currently supported";
return false;
}
}
auto geom = geomRet.value();
return std::make_unique<std::string>(WKTWriter().write(geom));
}

std::unique_ptr<std::string> Geography::asWKBHex() const {
auto geomRet = WKBReader().read(wkb);
if (!geomRet.ok()) {
LOG(ERROR) << geomRet.status();
return nullptr;
std::string Geography::asWKT() const { return WKTWriter().write(*this); }

std::string Geography::asWKB() const { return WKBWriter().write(*this); }

std::string Geography::asWKBHex() const { return folly::hexlify(WKBWriter().write(*this)); }

std::unique_ptr<S2Region> Geography::asS2() const { return GeoUtils::s2RegionFromGeography(*this); }

bool Geography::operator==(const Geography& rhs) const {
auto lhsShape = shape();
auto rhsShape = rhs.shape();
if (lhsShape != rhsShape) {
return false;
}
auto geom = geomRet.value();
return std::make_unique<std::string>(folly::hexlify(WKBWriter().write(geom)));
}

std::unique_ptr<Geometry> Geography::asGeometry() const {
auto geomRet = WKBReader().read(wkb);
if (!geomRet.ok()) {
LOG(ERROR) << geomRet.status();
return nullptr;
switch (lhsShape) {
case GeoShape::POINT: {
return point() == rhs.point();
}
case GeoShape::LINESTRING: {
return lineString() == rhs.lineString();
}
case GeoShape::POLYGON: {
return polygon() == rhs.polygon();
}
case GeoShape::UNKNOWN:
default: {
LOG(ERROR) << "Geography shapes other than Point/LineString/Polygon are not currently "
"supported";
return false;
}
}
auto geom = geomRet.value();
return std::make_unique<Geometry>(std::move(geom));
}

std::unique_ptr<S2Region> Geography::asS2() const {
auto geomRet = WKBReader().read(wkb);
if (!geomRet.ok()) {
LOG(ERROR) << geomRet.status();
return nullptr;
bool Geography::operator<(const Geography& rhs) const {
auto lhsShape = shape();
auto rhsShape = rhs.shape();
if (lhsShape != rhsShape) {
return lhsShape < rhsShape;
}
auto geom = geomRet.value();
geom.normalize();
return GeoUtils::s2RegionFromGeomtry(geom);

switch (lhsShape) {
case GeoShape::POINT: {
return point() < rhs.point();
}
case GeoShape::LINESTRING: {
return lineString() < rhs.lineString();
}
case GeoShape::POLYGON: {
return polygon() < rhs.polygon();
}
case GeoShape::UNKNOWN:
default: {
LOG(ERROR) << "Geography shapes other than Point/LineString/Polygon are not currently "
"supported";
return false;
}
}
return false;
}

} // namespace nebula

namespace std {

// Inject a customized hash function
std::size_t hash<nebula::Geography>::operator()(const nebula::Geography& h) const noexcept {
return hash<std::string>{}(h.wkb);
std::size_t hash<nebula::Geography>::operator()(const nebula::Geography& v) const noexcept {
std::string wkb = v.asWKB();
return hash<std::string>{}(wkb);
}

} // namespace std
Loading

0 comments on commit 53b8b2b

Please sign in to comment.