github-actions[bot] commented on code in PR #22933:
URL: https://github.com/apache/doris/pull/22933#discussion_r1311056800


##########
be/src/geo/util/GeoMultiPolygon.cpp:
##########
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoMultiPolygon.h"
+
+#include <sstream>
+
+#include "GeoMultiLineString.h"
+
+namespace doris {
+
+GeoMultiPolygon::GeoMultiPolygon() = default;
+GeoMultiPolygon::~GeoMultiPolygon() = default;
+
+GeoParseStatus GeoMultiPolygon::from_coords(
+        const GeoCoordinateListCollections& coord_list_collections) {
+    for (int i = 0; i < coord_list_collections.coords_list_collections.size(); 
i++) {
+        std::unique_ptr<doris::GeoPolygon> polygon = 
GeoPolygon::create_unique();
+        if 
(polygon->from_coords(*coord_list_collections.coords_list_collections[i]) !=
+            GeoParseStatus::GEO_PARSE_OK) {
+            return GEO_PARSE_COORD_INVALID;
+        }
+        geometries.emplace_back(polygon.release());
+    }
+    return GEO_PARSE_OK;
+}
+
+std::unique_ptr<GeoCoordinateListCollections> GeoMultiPolygon::to_coords() 
const {
+    std::unique_ptr<GeoCoordinateListCollections> coords_collections(
+            new GeoCoordinateListCollections());
+    for (std::size_t i = 0; i < get_num_polygon(); ++i) {
+        const GeoPolygon* polygon = (const 
GeoPolygon*)GeoCollection::get_geometries_n(i);
+        if (polygon->is_empty()) continue;
+        std::unique_ptr<GeoCoordinateLists> coord = polygon->to_coords();
+        coords_collections->add(coord.release());
+    }
+    return coords_collections;
+}
+
+std::size_t GeoMultiPolygon::get_num_polygon() const {
+    return GeoCollection::get_num_geometries();
+}
+
+std::string GeoMultiPolygon::as_wkt() const {
+    std::stringstream ss;
+    ss << "MULTIPOLYGON ";
+    if (is_empty()) {
+        ss << "EMPTY";
+        return ss.str();
+    }
+
+    ss << "(";
+
+    for (int i = 0; i < get_num_polygon(); ++i) {
+        if (i != 0) {
+            ss << ", ";
+        }
+        const GeoPolygon* polygon = (const 
GeoPolygon*)GeoCollection::get_geometries_n(i);
+        if (polygon->is_empty()) {
+            ss << "EMPTY";
+        } else {
+            GeoPolygon::print_coords(ss, *polygon);
+        }
+    }
+    ss << ")";
+    return ss.str();
+}
+
+GeoPolygon* GeoMultiPolygon::get_polygon_n(std::size_t n) const {
+    return (GeoPolygon*)GeoCollection::get_geometries_n(n);
+}
+
+bool GeoMultiPolygon::contains(const GeoShape* shape) const {
+    return GeoCollection::contains(shape);
+}
+
+std::unique_ptr<GeoShape> GeoMultiPolygon::boundary() const {
+    std::unique_ptr<GeoMultiLineString> multi_linestring = 
GeoMultiLineString::create_unique();
+    if (is_empty()) {
+        multi_linestring->set_empty();
+        return multi_linestring;
+    }
+
+    std::unique_ptr<GeoCoordinateListCollections> coords_list_collections = 
to_coords();
+
+    if (coords_list_collections->coords_list_collections.size() == 1 &&
+        
coords_list_collections->coords_list_collections[0]->coords_list.size() == 1) {
+        std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+        linestring->from_coords(
+                
*coords_list_collections->coords_list_collections[0]->coords_list[0]);
+        return linestring;
+    }
+
+    for (int i = 0; i < 
coords_list_collections->coords_list_collections.size(); ++i) {
+        for (int j = 0; j < 
coords_list_collections->coords_list_collections[i]->coords_list.size();
+             ++j) {
+            std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+            linestring->from_coords(

Review Comment:
   warning: ignoring return value of function declared with 'nodiscard' 
attribute [clang-diagnostic-unused-result]
   ```cpp
               linestring->from_coords(
               ^
   ```
   



##########
be/src/geo/util/GeoPolygon.cpp:
##########
@@ -0,0 +1,279 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoPolygon.h"
+
+#include <s2/mutable_s2shape_index.h>
+#include <s2/s2polygon.h>
+#include <s2/util/coding/coder.h>
+
+#include <vector>
+
+#include "GeoMultiLineString.h"
+#include "GeoMultiPoint.h"
+
+namespace doris {
+
+GeoPolygon::GeoPolygon() : _polygon(new S2Polygon()) {}
+GeoPolygon::~GeoPolygon() = default;
+
+static bool is_loop_closed(const std::vector<S2Point>& points) {
+    if (points.empty()) {
+        return false;
+    }
+    if (points[0] != points[points.size() - 1]) {
+        return false;
+    }
+    return true;
+}
+
+// remove adjacent duplicate points
+static void remove_duplicate_points(std::vector<S2Point>* points) {
+    int lhs = 0;
+    int rhs = 1;
+    for (; rhs < points->size(); ++rhs) {
+        if ((*points)[rhs] != (*points)[lhs]) {
+            lhs++;
+            if (lhs != rhs) {
+                (*points)[lhs] = (*points)[rhs];
+            }
+        }
+    }
+    points->resize(lhs + 1);
+}
+
+GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop) {
+    // 1. convert all coordinates to points
+    std::vector<S2Point> points(coords.coords.size());
+    for (int i = 0; i < coords.coords.size(); ++i) {
+        auto res = GeoPoint::to_s2point(coords.coords[i].x, 
coords.coords[i].y, &points[i]);
+        if (res != GEO_PARSE_OK) {
+            return res;
+        }
+    }
+    // 2. check if it is a closed loop
+    if (!is_loop_closed(points)) {
+        return GEO_PARSE_LOOP_NOT_CLOSED;
+    }
+    // 3. remove duplicate points
+    remove_duplicate_points(&points);
+    // 4. remove last point
+    points.resize(points.size() - 1);
+    // 5. check if there is enough point
+    if (points.size() < 3) {
+        return GEO_PARSE_LOOP_LACK_VERTICES;
+    }
+    loop->reset(new S2Loop(points));
+    if (!(*loop)->IsValid()) {
+        return GEO_PARSE_LOOP_INVALID;
+    }
+    (*loop)->Normalize();
+    return GEO_PARSE_OK;
+}
+
+static GeoParseStatus to_s2polygon(const GeoCoordinateLists& coords_list,
+                                   std::unique_ptr<S2Polygon>* polygon) {
+    std::vector<std::unique_ptr<S2Loop>> loops(coords_list.coords_list.size());
+    for (int i = 0; i < coords_list.coords_list.size(); ++i) {
+        auto res = to_s2loop(*coords_list.coords_list[i], &loops[i]);
+        if (res != GEO_PARSE_OK) {
+            return res;
+        }
+        if (i != 0 && !(loops[0]->Contains(*loops[i]))) {
+            return GEO_PARSE_POLYGON_NOT_HOLE;
+        }
+    }
+    polygon->reset(new S2Polygon(std::move(loops)));
+    return GEO_PARSE_OK;
+}
+
+bool GeoPolygon::is_valid() const {
+    return polygon()->IsValid();
+}
+
+bool GeoPolygon::is_closed() const {
+    return polygon()->is_full();
+}
+
+GeoParseStatus GeoPolygon::from_coords(const GeoCoordinateLists& list) {
+    return to_s2polygon(list, &_polygon);
+}
+
+const std::unique_ptr<GeoCoordinateLists> GeoPolygon::to_coords() const {
+    std::unique_ptr<GeoCoordinateLists> coordss(new GeoCoordinateLists());
+    for (int i = 0; i < GeoPolygon::num_loops(); ++i) {
+        std::unique_ptr<GeoCoordinates> coords(new GeoCoordinates());
+        S2Loop* loop = GeoPolygon::get_loop(i);
+        for (int j = 0; j < loop->num_vertices(); ++j) {
+            GeoCoordinate coord;
+            coord.x = std::stod(
+                    absl::StrFormat("%.13f", 
S2LatLng::Longitude(loop->vertex(j)).degrees()));
+            coord.y = std::stod(
+                    absl::StrFormat("%.13f", 
S2LatLng::Latitude(loop->vertex(j)).degrees()));
+            coords->add(coord);
+            if (j == loop->num_vertices() - 1) {
+                coord.x = std::stod(
+                        absl::StrFormat("%.13f", 
S2LatLng::Longitude(loop->vertex(0)).degrees()));
+                coord.y = std::stod(
+                        absl::StrFormat("%.13f", 
S2LatLng::Latitude(loop->vertex(0)).degrees()));
+                coords->add(coord);
+            }
+        }
+        coordss->add(coords.release());
+    }
+    return coordss;
+}
+
+GeoParseStatus GeoPolygon::from_s2loop(std::vector<std::unique_ptr<S2Loop>>& 
loops) {
+    _polygon.reset(new S2Polygon(std::move(loops)));
+    return GEO_PARSE_OK;
+}
+
+GeoParseStatus GeoPolygon::from_s2polygon(std::unique_ptr<S2Polygon> 
s2polygon) {
+    _polygon.reset(s2polygon.release());
+    return GEO_PARSE_OK;
+}
+
+double GeoPolygon::get_perimeter() const {
+    double perimeter = 0;
+    std::unique_ptr<S2Shape> shape = get_s2shape();
+    for (int i = 0; i < shape->num_edges(); i++) {
+        S2Shape::Edge e = shape->edge(i);
+        S1ChordAngle angle(e.v0, e.v1);
+        perimeter += angle.radians();
+    }
+    return perimeter;
+}
+
+std::unique_ptr<S2Shape> GeoPolygon::get_s2shape() const {
+    return std::make_unique<S2Polygon::Shape>(_polygon.get());
+}
+
+bool GeoPolygon::contains(const GeoShape* rhs) const {
+    switch (rhs->type()) {
+    case GEO_SHAPE_POINT: {
+        const GeoPoint* point = (const GeoPoint*)rhs;
+        return _polygon->Contains(*point->point());
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        const GeoLineString* line = (const GeoLineString*)rhs;
+        return _polygon->Contains(*line->polyline());
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* polygon = (const GeoPolygon*)rhs;
+        return _polygon->Contains(*polygon->polygon());
+    }
+    default:
+        return false;
+    }
+}
+
+void GeoPolygon::print_coords(std::ostream& os, const GeoPolygon& polygon) {
+    os << "(";
+    for (int i = 0; i < polygon.num_loops(); ++i) {
+        if (i != 0) {
+            os << ", ";
+        }
+        os << "(";
+        const S2Loop* loop = polygon.get_loop(i);
+        for (int j = 0; j < loop->num_vertices(); ++j) {
+            if (j != 0) {
+                os << ", ";
+            }
+            GeoPoint::print_s2point(os, loop->vertex(j));
+        }
+        os << ", ";
+        GeoPoint::print_s2point(os, loop->vertex(0));
+        os << ")";
+    }
+    os << ")";
+}
+
+std::string GeoPolygon::as_wkt() const {
+    std::stringstream ss;
+    ss << "POLYGON ";
+
+    if (is_empty()) {
+        ss << "EMPTY";
+        return ss.str();
+    }
+
+    print_coords(ss, *this);
+    return ss.str();
+}
+
+int GeoPolygon::num_loops() const {
+    return _polygon->num_loops();
+}
+
+double GeoPolygon::get_area() const {
+    return _polygon->GetArea();
+}
+
+S2Loop* GeoPolygon::get_loop(int i) const {
+    return _polygon->loop(i);
+}
+
+std::size_t GeoPolygon::get_num_point() const {
+    if (is_empty()) return 0;
+    return _polygon->num_vertices() + _polygon->num_loops();
+}
+
+std::unique_ptr<GeoShape> GeoPolygon::boundary() const {
+    std::unique_ptr<GeoMultiLineString> multi_linestring = 
GeoMultiLineString::create_unique();
+    if (is_empty()) {
+        multi_linestring->set_empty();
+        return multi_linestring;
+    }
+
+    std::unique_ptr<GeoCoordinateLists> coords_list = to_coords();
+
+    if (coords_list->coords_list.size() == 1) {
+        std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+        linestring->from_coords(*coords_list->coords_list[0]);

Review Comment:
   warning: ignoring return value of function declared with 'nodiscard' 
attribute [clang-diagnostic-unused-result]
   ```cpp
           linestring->from_coords(*coords_list->coords_list[0]);
           ^
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;

Review Comment:
   warning: function 'type' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual GeoShapeType type() const = 0;
   ```
   



##########
be/src/geo/util/GeoShape.cpp:
##########
@@ -0,0 +1,572 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoShape.h"
+
+#include <s2/mutable_s2shape_index.h>
+#include <s2/s2boolean_operation.h>
+#include <s2/s2buffer_operation.h>
+#include <s2/s2builderutil_lax_polygon_layer.h>
+#include <s2/s2builderutil_s2polygon_layer.h>
+#include <s2/s2centroids.h>
+#include <s2/s2closest_edge_query.h>
+#include <s2/s2closest_point_query.h>
+#include <s2/s2earth.h>
+#include <s2/s2error.h>
+#include <s2/s2lax_polygon_shape.h>
+#include <s2/s2point_vector_shape.h>
+#include <s2/s2polygon.h>
+#include <s2/s2polyline.h>
+
+#include "GeoCircle.h"
+#include "GeoCollection.h"
+#include "GeoLineString.h"
+#include "GeoMultiLineString.h"
+#include "GeoMultiPoint.h"
+#include "GeoMultiPolygon.h"
+#include "GeoPoint.h"
+#include "GeoPolygon.h"
+#include "geo/geo_tobinary.h"
+#include "geo/geo_tojson.h"
+#include "geo/geojson_parse.h"
+#include "geo/wkb_parse.h"
+#include "geo/wkt_parse.h"
+
+namespace doris {
+
+size_t hash_coord(const GeoCoordinate& coord) {
+    return std::hash<double>()(coord.x) ^ std::hash<double>()(coord.y);
+}
+
+bool GeoShape::is_ring() const {
+    if (type() == GEO_SHAPE_LINE_STRING && is_closed()) {
+        const GeoLineString* line_string = (const GeoLineString*)this;
+        std::unique_ptr<GeoCoordinates> 
coords(line_string->to_coords_ptr().release());
+        std::set<GeoCoordinate, CompareA> coords_set(coords->coords.begin(), 
coords->coords.end());
+        /*for (int i = 0; i < line_string->get_num_point() - 1; ++i) {
+                auto [it, inserted] = coords_set.insert(coords->coords[i]);
+                if (!inserted) {
+                    return false;
+                }
+            }*/
+        return coords->coords.size() - 1 == coords_set.size();
+    } else {
+        //这里应该报错
+        return false;
+    }
+}
+
+bool GeoShape::decode_from(const void* data, size_t& data_size) {
+    char reserved_byte = ((const char*)data)[0];
+    if (reserved_byte == 0X01) {
+        set_empty();
+        return true;
+    }
+
+    char type_byte = ((const char*)data)[1];
+    if (reserved_byte != 0X00 || type_byte != type()) {
+        return false;
+    }
+
+    std::memcpy(&data_size, (const char*)data + 2, sizeof(data_size));
+
+    return decode((const char*)data + 10, data_size);
+}
+
+void GeoShape::encode_to(std::string* buf) {
+    size_t data_size = 0;
+    // Whether the first byte storage is empty, 0X01 is empty.6
+    if (is_empty()) {
+        buf->push_back(0X01);
+        buf->push_back((char)type());
+        buf->append(reinterpret_cast<const char*>(&data_size), 
sizeof(data_size));
+        return;
+    }
+    buf->push_back(0X00);
+    buf->push_back((char)type());
+    buf->append(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
+    encode(buf, data_size);
+    std::memcpy(&(*buf)[2], &data_size, sizeof(data_size));
+}
+
+GeoShape* GeoShape::from_wkt(const char* data, size_t size, GeoParseStatus* 
status) {
+    GeoShape* shape = nullptr;
+    *status = WktParse::parse_wkt(data, size, &shape);
+    return shape;
+}
+
+GeoShape* GeoShape::from_wkb(const char* data, size_t size, GeoParseStatus* 
status) {
+    std::stringstream wkb;
+
+    for (int i = 0; i < size; ++i) {
+        if ((i == 1 && wkb.str() == "x") || (i == 2 && wkb.str() == "\\x")) {
+            wkb.str(std::string());
+        }
+        wkb << *data;
+        data++;
+    }
+    GeoShape* shape = nullptr;
+    *status = WkbParse::parse_wkb(wkb, &shape);
+    return shape;
+}
+
+std::string GeoShape::as_binary(GeoShape* rhs, int is_hex) {
+    std::string res;
+    if (toBinary::geo_tobinary(rhs, &res, is_hex)) {
+        return res;
+    }
+    return res;
+}
+
+std::string GeoShape::geo_tohex(std::string binary) {
+    return toBinary::to_hex(binary);
+}
+
+GeoShape* GeoShape::from_geojson(const char* data, size_t size, 
GeoParseStatus* status) {
+    std::string geojson(data, size);
+
+    GeoShape* shape = nullptr;
+    *status = GeoJsonParse::parse_geojson(geojson, &shape);
+    return shape;
+}
+
+bool GeoShape::as_geojson(std::string& res) {
+    return toGeoJson::geo_tojson(this, res);
+}
+
+GeoShape* GeoShape::from_encoded(const void* ptr, size_t& size) {
+    std::unique_ptr<GeoShape> shape;
+    switch (((const char*)ptr)[1]) {
+    case GEO_SHAPE_POINT: {
+        shape.reset(GeoPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        shape.reset(GeoLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        shape.reset(GeoPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        shape.reset(GeoMultiPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        shape.reset(GeoMultiLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        shape.reset(GeoMultiPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        shape.reset(GeoCollection::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_CIRCLE: {
+        shape.reset(GeoCircle::create_unique().release());
+        break;
+    }
+    default:
+        return nullptr;
+    }
+    auto res = shape->decode_from(ptr, size); //shape->decode((const char *) 
ptr + 2, size - 2);
+    if (!res) {
+        return nullptr;
+    }
+
+    //shape->decode_from(ptr,size);
+    return shape.release();
+}
+
+bool GeoShape::intersects(GeoShape* shape) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return false;
+    }
+
+    return S2BooleanOperation::Intersects(shape_index1, shape_index2);
+}
+
+bool GeoShape::ComputeArea(double* area, std::string square_unit) {
+    if (is_empty()) {
+        *area = 0;
+        return true;
+    }
+
+    std::vector<double> steradians;
+    switch (type()) {
+    case GEO_SHAPE_CIRCLE: {
+        const GeoCircle* circle = (const GeoCircle*)this;
+        steradians.emplace_back(circle->get_area());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* polygon = (const GeoPolygon*)this;
+        steradians.emplace_back(polygon->get_area());
+        break;
+    }
+    case GEO_SHAPE_POINT:
+    case GEO_SHAPE_LINE_STRING:
+    case GEO_SHAPE_MULTI_POINT:
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        *area = 0;
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            switch (collection->get_geometries_n(i)->type()) {
+            case GEO_SHAPE_POLYGON: {
+                const GeoPolygon* polygon = (const 
GeoPolygon*)collection->get_geometries_n(i);
+                steradians.emplace_back(polygon->get_area());
+                break;
+            }
+            default:
+                steradians.emplace_back(0);
+            }
+        }
+        break;
+    }
+    default:
+        return false;
+    }
+
+    if (square_unit.compare("square_meters") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareMeters(s) + *area;
+        }
+        return true;
+    } else if (square_unit.compare("square_km") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareKm(s) + *area;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+double GeoShape::get_length() const {
+    double length = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_LINE_STRING: {
+        return S2Earth::RadiansToMeters(((const 
GeoLineString*)this)->length());
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 1) return length;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            if ((get_geometries_n(i)->type() == GEO_SHAPE_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_MULTI_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_GEOMETRY_COLLECTION) 
&&
+                !get_geometries_n(i)->is_empty()) {
+                length += get_geometries_n(i)->get_length();
+            }
+        }
+        return length;
+    }
+    default:
+        return length;
+    }
+}
+
+double GeoShape::get_perimeter() const {
+    double perimeter = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_POLYGON: {
+        return S2Earth::RadiansToMeters(((const 
GeoPolygon*)this)->get_perimeter());
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 2) return perimeter;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            perimeter += S2Earth::RadiansToMeters(
+                    ((const 
GeoLineString*)get_geometries_n(i))->get_perimeter());
+        }
+        return perimeter;
+    }
+    default:
+        return perimeter;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::get_centroid() const {
+    std::unique_ptr<GeoPoint> centroid = GeoPoint::create_unique();
+    if (is_empty()) {
+        centroid->set_empty();
+        return centroid;
+    }
+
+    S2Point centroid_vector(0, 0, 0);
+
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        
centroid->from_s2point(const_cast<S2Point*>(((GeoPoint*)this)->point()));
+        return centroid;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        S2Point s2_point = ((const 
GeoLineString*)this)->polyline()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_POLYGON: {
+        S2Point s2_point = ((const GeoPolygon*)this)->polygon()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        std::vector<S2Point> points;
+        const GeoMultiPoint* multi_point = (const GeoMultiPoint*)this;
+        for (int i = 0; i < multi_point->get_num_point(); ++i) {
+            if (multi_point->get_point_n(i)->is_empty()) continue;
+            points.emplace_back(*multi_point->get_point_n(i)->point());
+        }
+
+        auto shape = std::make_unique<S2PointVectorShape>(points);
+        for (int j = 0; j < shape->num_edges(); j++) {
+            S2Shape::Edge e = shape->edge(j);
+            centroid_vector += e.v0;
+        }
+
+        centroid->from_s2point(&centroid_vector);
+
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        const GeoMultiLineString* multi_line_string = (const 
GeoMultiLineString*)this;
+        for (int i = 0; i < multi_line_string->get_num_line(); ++i) {
+            if (multi_line_string->get_line_string_n(i)->is_empty()) continue;
+            auto shape = std::make_unique<S2Polyline::Shape>(
+                    multi_line_string->get_line_string_n(i)->polyline());
+            for (int j = 0; j < shape->num_edges(); j++) {
+                S2Shape::Edge e = shape->edge(j);
+                centroid_vector += S2::TrueCentroid(e.v0, e.v1);
+            }
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = (const GeoMultiPolygon*)this;
+        for (int i = 0; i < multi_polygon->get_num_polygon(); ++i) {
+            if (multi_polygon->get_polygon_n(i)->is_empty()) continue;
+            S2Point centroid_tmp = 
multi_polygon->get_polygon_n(i)->polygon()->GetCentroid();
+            centroid_vector += centroid_tmp;
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            GeoPoint* point = 
(GeoPoint*)collection->get_geometries_n(i)->get_centroid().release();
+            centroid_vector += *point->point();
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    default:
+        //报错
+        return nullptr;
+    }
+}
+
+bool GeoShape::get_type_string(std::string& type_string) const {
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        type_string = "ST_Point";
+        return true;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        type_string = "ST_LineString";
+        return true;
+    }
+    case GEO_SHAPE_POLYGON: {
+        type_string = "ST_Polygon";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        type_string = "ST_MultiPoint";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        type_string = "ST_MultiLineString";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        type_string = "ST_MultiPolygon";
+        return true;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        type_string = "ST_GeometryCollection";
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::find_closest_point(const GeoShape* shape) 
const {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return nullptr;
+    }
+
+    S2ClosestEdgeQuery query1(&shape_index1);
+
+    query1.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::ShapeIndexTarget target(&shape_index2);
+
+    const auto& result1 = query1.FindClosestEdge(&target);
+
+    if (result1.edge_id() == -1) {
+        //这里表示没找到最近的edge,应该返回失败,理论上不会走到这里,因为set_include_interiors(false);
+        return nullptr;
+    }
+
+    // Get the edge from index1 (edge1) that is closest to index2.
+    S2Shape::Edge edge1 = query1.GetEdge(result1);
+
+    // Now find the edge from index2 (edge2) that is closest to edge1.
+    S2ClosestEdgeQuery query2(&shape_index2);
+    query2.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::EdgeTarget target2(edge1.v0, edge1.v1);
+    auto result2 = query2.FindClosestEdge(&target2);
+
+    // what if result2 has no edges?
+    if (result2.is_interior()) {
+        //这里应该返回报错
+        return nullptr;
+        //throw Exception("S2ClosestEdgeQuery result is interior!");
+    }
+
+    S2Shape::Edge edge2 = query2.GetEdge(result2);
+
+    std::unique_ptr<GeoPoint> res_point = GeoPoint::create_unique();
+
+    S2Point s2Point = S2::GetEdgePairClosestPoints(edge1.v0, edge1.v1, 
edge2.v0, edge2.v1).first;
+    res_point->from_s2point(&s2Point);
+
+    return res_point;
+}
+
+bool GeoShape::dwithin(const GeoShape* shape, double distance) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return false;
+    }
+
+    S2ClosestEdgeQuery query(&shape_index1);
+    S2ClosestEdgeQuery::ShapeIndexTarget target(&shape_index2);
+
+    const auto& result = query.FindClosestEdge(&target);
+
+    return S2Earth::RadiansToMeters(result.distance().ToAngle().radians()) <= 
distance;
+}
+
+std::unique_ptr<GeoShape> one_geo_buffer(S2BufferOperation::Options& options,
+                                         MutableS2ShapeIndex& shape_index) {
+    auto output = std::make_unique<S2Polygon>();
+    S2BufferOperation 
op(std::make_unique<s2builderutil::S2PolygonLayer>(output.get()), options);
+
+    op.AddShapeIndex(shape_index);
+
+    S2Error error;
+    if (!op.Build(&error)) {
+        //这里应该返回报错
+        return nullptr;
+    }
+    std::unique_ptr<GeoPolygon> res_polygon = GeoPolygon::create_unique();
+    res_polygon->from_s2polygon(std::move(output));
+    return res_polygon;
+}
+
+std::unique_ptr<GeoShape> GeoShape::buffer(double buffer_radius, double 
num_seg_quarter_circle,
+                                           std::string end_cap, std::string 
side) {
+    S2BufferOperation::Options options;
+    options.set_buffer_radius(S2Earth::MetersToAngle(buffer_radius));
+    options.set_circle_segments(num_seg_quarter_circle * 4);
+
+    if (end_cap == "ROUND") {
+        options.set_end_cap_style(S2BufferOperation::EndCapStyle::ROUND);
+    } else if (end_cap == "FLAT") {
+        options.set_end_cap_style(S2BufferOperation::EndCapStyle::FLAT);
+    } else {
+        //这里应该返回不正确的 end_cap 或者在function.cpp校验。
+        return nullptr;
+    }
+
+    if (side == "BOTH") {
+        options.set_polyline_side(S2BufferOperation::PolylineSide::BOTH);
+    } else if (end_cap == "LEFT") {
+        options.set_polyline_side(S2BufferOperation::PolylineSide::LEFT);
+    } else if (end_cap == "RIGHT") {
+        options.set_polyline_side(S2BufferOperation::PolylineSide::RIGHT);
+    } else {
+        //这里应该返回不正确的 end_cap 或者在function.cpp校验。
+        return nullptr;
+    }
+
+    switch (type()) {
+    case GEO_SHAPE_POINT:
+    case GEO_SHAPE_LINE_STRING:
+    case GEO_SHAPE_POLYGON: {
+        MutableS2ShapeIndex shape_index;
+        if (!this->add_to_s2shape_index(shape_index)) {
+            //这里应该返回报错
+            return nullptr;
+        }
+        return one_geo_buffer(options, shape_index);
+    }
+    case GEO_SHAPE_MULTI_POINT:
+    case GEO_SHAPE_MULTI_LINE_STRING:
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        std::unique_ptr<GeoMultiPolygon> res_multi_polygon = 
GeoMultiPolygon::create_unique();
+        for (int i = 0; i < this->get_num_geometries(); ++i) {
+            MutableS2ShapeIndex shape_index;
+            if (this->get_geometries_n(i)->is_empty()) continue;
+            if (!this->get_geometries_n(i)->add_to_s2shape_index(shape_index)) 
{
+                //这里应该返回报错
+                return nullptr;
+            }
+            res_multi_polygon->add_one_geometry(one_geo_buffer(options, 
shape_index).release());

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   dex shape_index; {
   }
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {
+        if ((type() == GEO_SHAPE_MULTI_POINT || type() == 
GEO_SHAPE_MULTI_LINE_STRING ||
+             type() == GEO_SHAPE_MULTI_POLYGON || type() == 
GEO_SHAPE_GEOMETRY_COLLECTION) &&
+            !is_empty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool is_ring() const;

Review Comment:
   warning: function 'is_ring' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] bool is_ring() const;
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {
+        if ((type() == GEO_SHAPE_MULTI_POINT || type() == 
GEO_SHAPE_MULTI_LINE_STRING ||
+             type() == GEO_SHAPE_MULTI_POLYGON || type() == 
GEO_SHAPE_GEOMETRY_COLLECTION) &&
+            !is_empty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool is_ring() const;
+
+    bool is_empty() const { return empty; }
+
+    void set_empty() { empty = true; }
+
+    [[nodiscard]] virtual int get_dimension() const = 0;
+
+    // decode from serialized data
+    static GeoShape* from_encoded(const void* data, size_t& size);
+
+    void encode_to(std::string* buf);
+
+    bool decode_from(const void* data, size_t& data_size);
+
+    // Returns the number of geometries in this collection
+    // (or 1 if this is not a collection)
+    virtual std::size_t get_num_geometries() const { return 1; }

Review Comment:
   warning: function 'get_num_geometries' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual std::size_t get_num_geometries() const { return 1; 
}
   ```
   



##########
be/test/geo/geo_types_test.cpp:
##########
@@ -15,15 +15,16 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include "geo/geo_types.h"
-
 #include <gtest/gtest-message.h>
 #include <gtest/gtest-test-part.h>
 #include <string.h>
 
 #include <ostream>
 
 #include "common/logging.h"

Review Comment:
   warning: 'common/logging.h' file not found [clang-diagnostic-error]
   ```cpp
   #include "common/logging.h"
            ^
   ```
   



##########
be/src/geo/util/GeoPolygon.cpp:
##########
@@ -0,0 +1,279 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoPolygon.h"
+
+#include <s2/mutable_s2shape_index.h>
+#include <s2/s2polygon.h>
+#include <s2/util/coding/coder.h>
+
+#include <vector>
+
+#include "GeoMultiLineString.h"
+#include "GeoMultiPoint.h"
+
+namespace doris {
+
+GeoPolygon::GeoPolygon() : _polygon(new S2Polygon()) {}
+GeoPolygon::~GeoPolygon() = default;
+
+static bool is_loop_closed(const std::vector<S2Point>& points) {
+    if (points.empty()) {
+        return false;
+    }
+    if (points[0] != points[points.size() - 1]) {
+        return false;
+    }
+    return true;
+}
+
+// remove adjacent duplicate points
+static void remove_duplicate_points(std::vector<S2Point>* points) {
+    int lhs = 0;
+    int rhs = 1;
+    for (; rhs < points->size(); ++rhs) {
+        if ((*points)[rhs] != (*points)[lhs]) {
+            lhs++;
+            if (lhs != rhs) {
+                (*points)[lhs] = (*points)[rhs];
+            }
+        }
+    }
+    points->resize(lhs + 1);
+}
+
+GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop) {
+    // 1. convert all coordinates to points
+    std::vector<S2Point> points(coords.coords.size());
+    for (int i = 0; i < coords.coords.size(); ++i) {
+        auto res = GeoPoint::to_s2point(coords.coords[i].x, 
coords.coords[i].y, &points[i]);
+        if (res != GEO_PARSE_OK) {
+            return res;
+        }
+    }
+    // 2. check if it is a closed loop
+    if (!is_loop_closed(points)) {
+        return GEO_PARSE_LOOP_NOT_CLOSED;
+    }
+    // 3. remove duplicate points
+    remove_duplicate_points(&points);
+    // 4. remove last point
+    points.resize(points.size() - 1);
+    // 5. check if there is enough point
+    if (points.size() < 3) {
+        return GEO_PARSE_LOOP_LACK_VERTICES;
+    }
+    loop->reset(new S2Loop(points));
+    if (!(*loop)->IsValid()) {
+        return GEO_PARSE_LOOP_INVALID;
+    }
+    (*loop)->Normalize();
+    return GEO_PARSE_OK;
+}
+
+static GeoParseStatus to_s2polygon(const GeoCoordinateLists& coords_list,
+                                   std::unique_ptr<S2Polygon>* polygon) {
+    std::vector<std::unique_ptr<S2Loop>> loops(coords_list.coords_list.size());
+    for (int i = 0; i < coords_list.coords_list.size(); ++i) {
+        auto res = to_s2loop(*coords_list.coords_list[i], &loops[i]);
+        if (res != GEO_PARSE_OK) {
+            return res;
+        }
+        if (i != 0 && !(loops[0]->Contains(*loops[i]))) {
+            return GEO_PARSE_POLYGON_NOT_HOLE;
+        }
+    }
+    polygon->reset(new S2Polygon(std::move(loops)));
+    return GEO_PARSE_OK;
+}
+
+bool GeoPolygon::is_valid() const {
+    return polygon()->IsValid();
+}
+
+bool GeoPolygon::is_closed() const {
+    return polygon()->is_full();
+}
+
+GeoParseStatus GeoPolygon::from_coords(const GeoCoordinateLists& list) {
+    return to_s2polygon(list, &_polygon);
+}
+
+const std::unique_ptr<GeoCoordinateLists> GeoPolygon::to_coords() const {
+    std::unique_ptr<GeoCoordinateLists> coordss(new GeoCoordinateLists());
+    for (int i = 0; i < GeoPolygon::num_loops(); ++i) {
+        std::unique_ptr<GeoCoordinates> coords(new GeoCoordinates());
+        S2Loop* loop = GeoPolygon::get_loop(i);
+        for (int j = 0; j < loop->num_vertices(); ++j) {
+            GeoCoordinate coord;
+            coord.x = std::stod(
+                    absl::StrFormat("%.13f", 
S2LatLng::Longitude(loop->vertex(j)).degrees()));
+            coord.y = std::stod(
+                    absl::StrFormat("%.13f", 
S2LatLng::Latitude(loop->vertex(j)).degrees()));
+            coords->add(coord);
+            if (j == loop->num_vertices() - 1) {
+                coord.x = std::stod(
+                        absl::StrFormat("%.13f", 
S2LatLng::Longitude(loop->vertex(0)).degrees()));
+                coord.y = std::stod(
+                        absl::StrFormat("%.13f", 
S2LatLng::Latitude(loop->vertex(0)).degrees()));
+                coords->add(coord);
+            }
+        }
+        coordss->add(coords.release());
+    }
+    return coordss;
+}
+
+GeoParseStatus GeoPolygon::from_s2loop(std::vector<std::unique_ptr<S2Loop>>& 
loops) {
+    _polygon.reset(new S2Polygon(std::move(loops)));
+    return GEO_PARSE_OK;
+}
+
+GeoParseStatus GeoPolygon::from_s2polygon(std::unique_ptr<S2Polygon> 
s2polygon) {
+    _polygon.reset(s2polygon.release());
+    return GEO_PARSE_OK;
+}
+
+double GeoPolygon::get_perimeter() const {
+    double perimeter = 0;
+    std::unique_ptr<S2Shape> shape = get_s2shape();
+    for (int i = 0; i < shape->num_edges(); i++) {
+        S2Shape::Edge e = shape->edge(i);
+        S1ChordAngle angle(e.v0, e.v1);
+        perimeter += angle.radians();
+    }
+    return perimeter;
+}
+
+std::unique_ptr<S2Shape> GeoPolygon::get_s2shape() const {
+    return std::make_unique<S2Polygon::Shape>(_polygon.get());
+}
+
+bool GeoPolygon::contains(const GeoShape* rhs) const {
+    switch (rhs->type()) {
+    case GEO_SHAPE_POINT: {
+        const GeoPoint* point = (const GeoPoint*)rhs;
+        return _polygon->Contains(*point->point());
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        const GeoLineString* line = (const GeoLineString*)rhs;
+        return _polygon->Contains(*line->polyline());
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* polygon = (const GeoPolygon*)rhs;
+        return _polygon->Contains(*polygon->polygon());
+    }
+    default:
+        return false;
+    }
+}
+
+void GeoPolygon::print_coords(std::ostream& os, const GeoPolygon& polygon) {
+    os << "(";
+    for (int i = 0; i < polygon.num_loops(); ++i) {
+        if (i != 0) {
+            os << ", ";
+        }
+        os << "(";
+        const S2Loop* loop = polygon.get_loop(i);
+        for (int j = 0; j < loop->num_vertices(); ++j) {
+            if (j != 0) {
+                os << ", ";
+            }
+            GeoPoint::print_s2point(os, loop->vertex(j));
+        }
+        os << ", ";
+        GeoPoint::print_s2point(os, loop->vertex(0));
+        os << ")";
+    }
+    os << ")";
+}
+
+std::string GeoPolygon::as_wkt() const {
+    std::stringstream ss;
+    ss << "POLYGON ";
+
+    if (is_empty()) {
+        ss << "EMPTY";
+        return ss.str();
+    }
+
+    print_coords(ss, *this);
+    return ss.str();
+}
+
+int GeoPolygon::num_loops() const {
+    return _polygon->num_loops();
+}
+
+double GeoPolygon::get_area() const {
+    return _polygon->GetArea();
+}
+
+S2Loop* GeoPolygon::get_loop(int i) const {
+    return _polygon->loop(i);
+}
+
+std::size_t GeoPolygon::get_num_point() const {
+    if (is_empty()) return 0;
+    return _polygon->num_vertices() + _polygon->num_loops();
+}
+
+std::unique_ptr<GeoShape> GeoPolygon::boundary() const {
+    std::unique_ptr<GeoMultiLineString> multi_linestring = 
GeoMultiLineString::create_unique();
+    if (is_empty()) {
+        multi_linestring->set_empty();
+        return multi_linestring;
+    }
+
+    std::unique_ptr<GeoCoordinateLists> coords_list = to_coords();
+
+    if (coords_list->coords_list.size() == 1) {
+        std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+        linestring->from_coords(*coords_list->coords_list[0]);
+        return linestring;
+    }
+
+    for (int i = 0; i < coords_list->coords_list.size(); ++i) {
+        std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+        linestring->from_coords(*coords_list->coords_list[i]);

Review Comment:
   warning: ignoring return value of function declared with 'nodiscard' 
attribute [clang-diagnostic-unused-result]
   ```cpp
           linestring->from_coords(*coords_list->coords_list[i]);
           ^
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }

Review Comment:
   warning: function 'is_valid' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual bool is_valid() const { return false; }
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }

Review Comment:
   warning: function 'is_closed' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual bool is_closed() const { return false; }
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H

Review Comment:
   warning: macro is not used [clang-diagnostic-unused-macros]
   ```cpp
   #define DORIS_GEOSHAPE_H
           ^
   ```
   



##########
be/src/geo/util/GeoMultiPolygon.cpp:
##########
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoMultiPolygon.h"
+
+#include <sstream>
+
+#include "GeoMultiLineString.h"
+
+namespace doris {
+
+GeoMultiPolygon::GeoMultiPolygon() = default;
+GeoMultiPolygon::~GeoMultiPolygon() = default;
+
+GeoParseStatus GeoMultiPolygon::from_coords(
+        const GeoCoordinateListCollections& coord_list_collections) {
+    for (int i = 0; i < coord_list_collections.coords_list_collections.size(); 
i++) {
+        std::unique_ptr<doris::GeoPolygon> polygon = 
GeoPolygon::create_unique();
+        if 
(polygon->from_coords(*coord_list_collections.coords_list_collections[i]) !=
+            GeoParseStatus::GEO_PARSE_OK) {
+            return GEO_PARSE_COORD_INVALID;
+        }
+        geometries.emplace_back(polygon.release());
+    }
+    return GEO_PARSE_OK;
+}
+
+std::unique_ptr<GeoCoordinateListCollections> GeoMultiPolygon::to_coords() 
const {
+    std::unique_ptr<GeoCoordinateListCollections> coords_collections(
+            new GeoCoordinateListCollections());
+    for (std::size_t i = 0; i < get_num_polygon(); ++i) {
+        const GeoPolygon* polygon = (const 
GeoPolygon*)GeoCollection::get_geometries_n(i);
+        if (polygon->is_empty()) continue;
+        std::unique_ptr<GeoCoordinateLists> coord = polygon->to_coords();
+        coords_collections->add(coord.release());
+    }
+    return coords_collections;
+}
+
+std::size_t GeoMultiPolygon::get_num_polygon() const {
+    return GeoCollection::get_num_geometries();
+}
+
+std::string GeoMultiPolygon::as_wkt() const {
+    std::stringstream ss;
+    ss << "MULTIPOLYGON ";
+    if (is_empty()) {
+        ss << "EMPTY";
+        return ss.str();
+    }
+
+    ss << "(";
+
+    for (int i = 0; i < get_num_polygon(); ++i) {
+        if (i != 0) {
+            ss << ", ";
+        }
+        const GeoPolygon* polygon = (const 
GeoPolygon*)GeoCollection::get_geometries_n(i);
+        if (polygon->is_empty()) {
+            ss << "EMPTY";
+        } else {
+            GeoPolygon::print_coords(ss, *polygon);
+        }
+    }
+    ss << ")";
+    return ss.str();
+}
+
+GeoPolygon* GeoMultiPolygon::get_polygon_n(std::size_t n) const {
+    return (GeoPolygon*)GeoCollection::get_geometries_n(n);
+}
+
+bool GeoMultiPolygon::contains(const GeoShape* shape) const {
+    return GeoCollection::contains(shape);
+}
+
+std::unique_ptr<GeoShape> GeoMultiPolygon::boundary() const {
+    std::unique_ptr<GeoMultiLineString> multi_linestring = 
GeoMultiLineString::create_unique();
+    if (is_empty()) {
+        multi_linestring->set_empty();
+        return multi_linestring;
+    }
+
+    std::unique_ptr<GeoCoordinateListCollections> coords_list_collections = 
to_coords();
+
+    if (coords_list_collections->coords_list_collections.size() == 1 &&
+        
coords_list_collections->coords_list_collections[0]->coords_list.size() == 1) {
+        std::unique_ptr<GeoLineString> linestring = 
GeoLineString::create_unique();
+        linestring->from_coords(

Review Comment:
   warning: ignoring return value of function declared with 'nodiscard' 
attribute [clang-diagnostic-unused-result]
   ```cpp
           linestring->from_coords(
           ^
   ```
   



##########
be/src/geo/util/GeoShape.cpp:
##########
@@ -0,0 +1,572 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoShape.h"
+
+#include <s2/mutable_s2shape_index.h>
+#include <s2/s2boolean_operation.h>
+#include <s2/s2buffer_operation.h>
+#include <s2/s2builderutil_lax_polygon_layer.h>
+#include <s2/s2builderutil_s2polygon_layer.h>
+#include <s2/s2centroids.h>
+#include <s2/s2closest_edge_query.h>
+#include <s2/s2closest_point_query.h>
+#include <s2/s2earth.h>
+#include <s2/s2error.h>
+#include <s2/s2lax_polygon_shape.h>
+#include <s2/s2point_vector_shape.h>
+#include <s2/s2polygon.h>
+#include <s2/s2polyline.h>
+
+#include "GeoCircle.h"
+#include "GeoCollection.h"
+#include "GeoLineString.h"
+#include "GeoMultiLineString.h"
+#include "GeoMultiPoint.h"
+#include "GeoMultiPolygon.h"
+#include "GeoPoint.h"
+#include "GeoPolygon.h"
+#include "geo/geo_tobinary.h"
+#include "geo/geo_tojson.h"
+#include "geo/geojson_parse.h"
+#include "geo/wkb_parse.h"
+#include "geo/wkt_parse.h"
+
+namespace doris {
+
+size_t hash_coord(const GeoCoordinate& coord) {
+    return std::hash<double>()(coord.x) ^ std::hash<double>()(coord.y);
+}
+
+bool GeoShape::is_ring() const {
+    if (type() == GEO_SHAPE_LINE_STRING && is_closed()) {
+        const GeoLineString* line_string = (const GeoLineString*)this;
+        std::unique_ptr<GeoCoordinates> 
coords(line_string->to_coords_ptr().release());
+        std::set<GeoCoordinate, CompareA> coords_set(coords->coords.begin(), 
coords->coords.end());
+        /*for (int i = 0; i < line_string->get_num_point() - 1; ++i) {
+                auto [it, inserted] = coords_set.insert(coords->coords[i]);
+                if (!inserted) {
+                    return false;
+                }
+            }*/
+        return coords->coords.size() - 1 == coords_set.size();
+    } else {
+        //这里应该报错
+        return false;
+    }
+}
+
+bool GeoShape::decode_from(const void* data, size_t& data_size) {
+    char reserved_byte = ((const char*)data)[0];
+    if (reserved_byte == 0X01) {
+        set_empty();
+        return true;
+    }
+
+    char type_byte = ((const char*)data)[1];
+    if (reserved_byte != 0X00 || type_byte != type()) {
+        return false;
+    }
+
+    std::memcpy(&data_size, (const char*)data + 2, sizeof(data_size));
+
+    return decode((const char*)data + 10, data_size);
+}
+
+void GeoShape::encode_to(std::string* buf) {
+    size_t data_size = 0;
+    // Whether the first byte storage is empty, 0X01 is empty.6
+    if (is_empty()) {
+        buf->push_back(0X01);
+        buf->push_back((char)type());
+        buf->append(reinterpret_cast<const char*>(&data_size), 
sizeof(data_size));
+        return;
+    }
+    buf->push_back(0X00);
+    buf->push_back((char)type());
+    buf->append(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
+    encode(buf, data_size);
+    std::memcpy(&(*buf)[2], &data_size, sizeof(data_size));
+}
+
+GeoShape* GeoShape::from_wkt(const char* data, size_t size, GeoParseStatus* 
status) {
+    GeoShape* shape = nullptr;
+    *status = WktParse::parse_wkt(data, size, &shape);
+    return shape;
+}
+
+GeoShape* GeoShape::from_wkb(const char* data, size_t size, GeoParseStatus* 
status) {
+    std::stringstream wkb;
+
+    for (int i = 0; i < size; ++i) {
+        if ((i == 1 && wkb.str() == "x") || (i == 2 && wkb.str() == "\\x")) {
+            wkb.str(std::string());
+        }
+        wkb << *data;
+        data++;
+    }
+    GeoShape* shape = nullptr;
+    *status = WkbParse::parse_wkb(wkb, &shape);
+    return shape;
+}
+
+std::string GeoShape::as_binary(GeoShape* rhs, int is_hex) {
+    std::string res;
+    if (toBinary::geo_tobinary(rhs, &res, is_hex)) {
+        return res;
+    }
+    return res;
+}
+
+std::string GeoShape::geo_tohex(std::string binary) {
+    return toBinary::to_hex(binary);
+}
+
+GeoShape* GeoShape::from_geojson(const char* data, size_t size, 
GeoParseStatus* status) {
+    std::string geojson(data, size);
+
+    GeoShape* shape = nullptr;
+    *status = GeoJsonParse::parse_geojson(geojson, &shape);
+    return shape;
+}
+
+bool GeoShape::as_geojson(std::string& res) {
+    return toGeoJson::geo_tojson(this, res);
+}
+
+GeoShape* GeoShape::from_encoded(const void* ptr, size_t& size) {
+    std::unique_ptr<GeoShape> shape;
+    switch (((const char*)ptr)[1]) {
+    case GEO_SHAPE_POINT: {
+        shape.reset(GeoPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        shape.reset(GeoLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        shape.reset(GeoPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        shape.reset(GeoMultiPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        shape.reset(GeoMultiLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        shape.reset(GeoMultiPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        shape.reset(GeoCollection::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_CIRCLE: {
+        shape.reset(GeoCircle::create_unique().release());
+        break;
+    }
+    default:
+        return nullptr;
+    }
+    auto res = shape->decode_from(ptr, size); //shape->decode((const char *) 
ptr + 2, size - 2);
+    if (!res) {
+        return nullptr;
+    }
+
+    //shape->decode_from(ptr,size);
+    return shape.release();
+}
+
+bool GeoShape::intersects(GeoShape* shape) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return false;
+    }
+
+    return S2BooleanOperation::Intersects(shape_index1, shape_index2);
+}
+
+bool GeoShape::ComputeArea(double* area, std::string square_unit) {
+    if (is_empty()) {
+        *area = 0;
+        return true;
+    }
+
+    std::vector<double> steradians;
+    switch (type()) {
+    case GEO_SHAPE_CIRCLE: {
+        const GeoCircle* circle = (const GeoCircle*)this;
+        steradians.emplace_back(circle->get_area());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* polygon = (const GeoPolygon*)this;
+        steradians.emplace_back(polygon->get_area());
+        break;
+    }
+    case GEO_SHAPE_POINT:
+    case GEO_SHAPE_LINE_STRING:
+    case GEO_SHAPE_MULTI_POINT:
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        *area = 0;
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            switch (collection->get_geometries_n(i)->type()) {
+            case GEO_SHAPE_POLYGON: {
+                const GeoPolygon* polygon = (const 
GeoPolygon*)collection->get_geometries_n(i);
+                steradians.emplace_back(polygon->get_area());
+                break;
+            }
+            default:
+                steradians.emplace_back(0);
+            }
+        }
+        break;
+    }
+    default:
+        return false;
+    }
+
+    if (square_unit.compare("square_meters") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareMeters(s) + *area;
+        }
+        return true;
+    } else if (square_unit.compare("square_km") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareKm(s) + *area;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+double GeoShape::get_length() const {
+    double length = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_LINE_STRING: {
+        return S2Earth::RadiansToMeters(((const 
GeoLineString*)this)->length());
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 1) return length;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            if ((get_geometries_n(i)->type() == GEO_SHAPE_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_MULTI_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_GEOMETRY_COLLECTION) 
&&
+                !get_geometries_n(i)->is_empty()) {
+                length += get_geometries_n(i)->get_length();
+            }
+        }
+        return length;
+    }
+    default:
+        return length;
+    }
+}
+
+double GeoShape::get_perimeter() const {
+    double perimeter = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_POLYGON: {
+        return S2Earth::RadiansToMeters(((const 
GeoPolygon*)this)->get_perimeter());
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 2) return perimeter;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            perimeter += S2Earth::RadiansToMeters(
+                    ((const 
GeoLineString*)get_geometries_n(i))->get_perimeter());
+        }
+        return perimeter;
+    }
+    default:
+        return perimeter;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::get_centroid() const {
+    std::unique_ptr<GeoPoint> centroid = GeoPoint::create_unique();
+    if (is_empty()) {
+        centroid->set_empty();
+        return centroid;
+    }
+
+    S2Point centroid_vector(0, 0, 0);
+
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        
centroid->from_s2point(const_cast<S2Point*>(((GeoPoint*)this)->point()));
+        return centroid;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        S2Point s2_point = ((const 
GeoLineString*)this)->polyline()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_POLYGON: {
+        S2Point s2_point = ((const GeoPolygon*)this)->polygon()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        std::vector<S2Point> points;
+        const GeoMultiPoint* multi_point = (const GeoMultiPoint*)this;
+        for (int i = 0; i < multi_point->get_num_point(); ++i) {
+            if (multi_point->get_point_n(i)->is_empty()) continue;
+            points.emplace_back(*multi_point->get_point_n(i)->point());
+        }
+
+        auto shape = std::make_unique<S2PointVectorShape>(points);
+        for (int j = 0; j < shape->num_edges(); j++) {
+            S2Shape::Edge e = shape->edge(j);
+            centroid_vector += e.v0;
+        }
+
+        centroid->from_s2point(&centroid_vector);
+
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        const GeoMultiLineString* multi_line_string = (const 
GeoMultiLineString*)this;
+        for (int i = 0; i < multi_line_string->get_num_line(); ++i) {
+            if (multi_line_string->get_line_string_n(i)->is_empty()) continue;
+            auto shape = std::make_unique<S2Polyline::Shape>(
+                    multi_line_string->get_line_string_n(i)->polyline());
+            for (int j = 0; j < shape->num_edges(); j++) {
+                S2Shape::Edge e = shape->edge(j);
+                centroid_vector += S2::TrueCentroid(e.v0, e.v1);
+            }
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = (const GeoMultiPolygon*)this;
+        for (int i = 0; i < multi_polygon->get_num_polygon(); ++i) {
+            if (multi_polygon->get_polygon_n(i)->is_empty()) continue;
+            S2Point centroid_tmp = 
multi_polygon->get_polygon_n(i)->polygon()->GetCentroid();
+            centroid_vector += centroid_tmp;
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            GeoPoint* point = 
(GeoPoint*)collection->get_geometries_n(i)->get_centroid().release();
+            centroid_vector += *point->point();
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    default:
+        //报错
+        return nullptr;
+    }
+}
+
+bool GeoShape::get_type_string(std::string& type_string) const {
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        type_string = "ST_Point";
+        return true;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        type_string = "ST_LineString";
+        return true;
+    }
+    case GEO_SHAPE_POLYGON: {
+        type_string = "ST_Polygon";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        type_string = "ST_MultiPoint";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        type_string = "ST_MultiLineString";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        type_string = "ST_MultiPolygon";
+        return true;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        type_string = "ST_GeometryCollection";
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::find_closest_point(const GeoShape* shape) 
const {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return nullptr;
+    }
+
+    S2ClosestEdgeQuery query1(&shape_index1);
+
+    query1.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::ShapeIndexTarget target(&shape_index2);
+
+    const auto& result1 = query1.FindClosestEdge(&target);
+
+    if (result1.edge_id() == -1) {
+        //这里表示没找到最近的edge,应该返回失败,理论上不会走到这里,因为set_include_interiors(false);
+        return nullptr;
+    }
+
+    // Get the edge from index1 (edge1) that is closest to index2.
+    S2Shape::Edge edge1 = query1.GetEdge(result1);
+
+    // Now find the edge from index2 (edge2) that is closest to edge1.
+    S2ClosestEdgeQuery query2(&shape_index2);
+    query2.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::EdgeTarget target2(edge1.v0, edge1.v1);
+    auto result2 = query2.FindClosestEdge(&target2);
+
+    // what if result2 has no edges?
+    if (result2.is_interior()) {
+        //这里应该返回报错
+        return nullptr;
+        //throw Exception("S2ClosestEdgeQuery result is interior!");
+    }
+
+    S2Shape::Edge edge2 = query2.GetEdge(result2);
+
+    std::unique_ptr<GeoPoint> res_point = GeoPoint::create_unique();
+
+    S2Point s2Point = S2::GetEdgePairClosestPoints(edge1.v0, edge1.v1, 
edge2.v0, edge2.v1).first;
+    res_point->from_s2point(&s2Point);
+
+    return res_point;
+}
+
+bool GeoShape::dwithin(const GeoShape* shape, double distance) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return false;
+    }
+
+    S2ClosestEdgeQuery query(&shape_index1);
+    S2ClosestEdgeQuery::ShapeIndexTarget target(&shape_index2);
+
+    const auto& result = query.FindClosestEdge(&target);
+
+    return S2Earth::RadiansToMeters(result.distance().ToAngle().radians()) <= 
distance;
+}
+
+std::unique_ptr<GeoShape> one_geo_buffer(S2BufferOperation::Options& options,
+                                         MutableS2ShapeIndex& shape_index) {
+    auto output = std::make_unique<S2Polygon>();
+    S2BufferOperation 
op(std::make_unique<s2builderutil::S2PolygonLayer>(output.get()), options);
+
+    op.AddShapeIndex(shape_index);
+
+    S2Error error;
+    if (!op.Build(&error)) {
+        //这里应该返回报错
+        return nullptr;
+    }
+    std::unique_ptr<GeoPolygon> res_polygon = GeoPolygon::create_unique();
+    res_polygon->from_s2polygon(std::move(output));
+    return res_polygon;
+}
+
+std::unique_ptr<GeoShape> GeoShape::buffer(double buffer_radius, double 
num_seg_quarter_circle,
+                                           std::string end_cap, std::string 
side) {
+    S2BufferOperation::Options options;

Review Comment:
   warning: method 'buffer' can be made const 
[readability-make-member-function-const]
   
   be/src/geo/util/GeoShape.cpp:515:
   ```diff
   -      std::string end_cap, std::string side) {
   +      std::string end_cap, std::string side) const {
   ```
   
   be/src/geo/util/GeoShape.h:121:
   ```diff
   -                                      std::string end_cap = "ROUND", 
std::string side = "BOTH");
   +                                      std::string end_cap = "ROUND", 
std::string side = "BOTH") const;
   ```
   



##########
be/src/geo/util/GeoShape.cpp:
##########
@@ -0,0 +1,572 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "GeoShape.h"
+
+#include <s2/mutable_s2shape_index.h>
+#include <s2/s2boolean_operation.h>
+#include <s2/s2buffer_operation.h>
+#include <s2/s2builderutil_lax_polygon_layer.h>
+#include <s2/s2builderutil_s2polygon_layer.h>
+#include <s2/s2centroids.h>
+#include <s2/s2closest_edge_query.h>
+#include <s2/s2closest_point_query.h>
+#include <s2/s2earth.h>
+#include <s2/s2error.h>
+#include <s2/s2lax_polygon_shape.h>
+#include <s2/s2point_vector_shape.h>
+#include <s2/s2polygon.h>
+#include <s2/s2polyline.h>
+
+#include "GeoCircle.h"
+#include "GeoCollection.h"
+#include "GeoLineString.h"
+#include "GeoMultiLineString.h"
+#include "GeoMultiPoint.h"
+#include "GeoMultiPolygon.h"
+#include "GeoPoint.h"
+#include "GeoPolygon.h"
+#include "geo/geo_tobinary.h"
+#include "geo/geo_tojson.h"
+#include "geo/geojson_parse.h"
+#include "geo/wkb_parse.h"
+#include "geo/wkt_parse.h"
+
+namespace doris {
+
+size_t hash_coord(const GeoCoordinate& coord) {
+    return std::hash<double>()(coord.x) ^ std::hash<double>()(coord.y);
+}
+
+bool GeoShape::is_ring() const {
+    if (type() == GEO_SHAPE_LINE_STRING && is_closed()) {
+        const GeoLineString* line_string = (const GeoLineString*)this;
+        std::unique_ptr<GeoCoordinates> 
coords(line_string->to_coords_ptr().release());
+        std::set<GeoCoordinate, CompareA> coords_set(coords->coords.begin(), 
coords->coords.end());
+        /*for (int i = 0; i < line_string->get_num_point() - 1; ++i) {
+                auto [it, inserted] = coords_set.insert(coords->coords[i]);
+                if (!inserted) {
+                    return false;
+                }
+            }*/
+        return coords->coords.size() - 1 == coords_set.size();
+    } else {
+        //这里应该报错
+        return false;
+    }
+}
+
+bool GeoShape::decode_from(const void* data, size_t& data_size) {
+    char reserved_byte = ((const char*)data)[0];
+    if (reserved_byte == 0X01) {
+        set_empty();
+        return true;
+    }
+
+    char type_byte = ((const char*)data)[1];
+    if (reserved_byte != 0X00 || type_byte != type()) {
+        return false;
+    }
+
+    std::memcpy(&data_size, (const char*)data + 2, sizeof(data_size));
+
+    return decode((const char*)data + 10, data_size);
+}
+
+void GeoShape::encode_to(std::string* buf) {
+    size_t data_size = 0;
+    // Whether the first byte storage is empty, 0X01 is empty.6
+    if (is_empty()) {
+        buf->push_back(0X01);
+        buf->push_back((char)type());
+        buf->append(reinterpret_cast<const char*>(&data_size), 
sizeof(data_size));
+        return;
+    }
+    buf->push_back(0X00);
+    buf->push_back((char)type());
+    buf->append(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
+    encode(buf, data_size);
+    std::memcpy(&(*buf)[2], &data_size, sizeof(data_size));
+}
+
+GeoShape* GeoShape::from_wkt(const char* data, size_t size, GeoParseStatus* 
status) {
+    GeoShape* shape = nullptr;
+    *status = WktParse::parse_wkt(data, size, &shape);
+    return shape;
+}
+
+GeoShape* GeoShape::from_wkb(const char* data, size_t size, GeoParseStatus* 
status) {
+    std::stringstream wkb;
+
+    for (int i = 0; i < size; ++i) {
+        if ((i == 1 && wkb.str() == "x") || (i == 2 && wkb.str() == "\\x")) {
+            wkb.str(std::string());
+        }
+        wkb << *data;
+        data++;
+    }
+    GeoShape* shape = nullptr;
+    *status = WkbParse::parse_wkb(wkb, &shape);
+    return shape;
+}
+
+std::string GeoShape::as_binary(GeoShape* rhs, int is_hex) {
+    std::string res;
+    if (toBinary::geo_tobinary(rhs, &res, is_hex)) {
+        return res;
+    }
+    return res;
+}
+
+std::string GeoShape::geo_tohex(std::string binary) {
+    return toBinary::to_hex(binary);
+}
+
+GeoShape* GeoShape::from_geojson(const char* data, size_t size, 
GeoParseStatus* status) {
+    std::string geojson(data, size);
+
+    GeoShape* shape = nullptr;
+    *status = GeoJsonParse::parse_geojson(geojson, &shape);
+    return shape;
+}
+
+bool GeoShape::as_geojson(std::string& res) {
+    return toGeoJson::geo_tojson(this, res);
+}
+
+GeoShape* GeoShape::from_encoded(const void* ptr, size_t& size) {
+    std::unique_ptr<GeoShape> shape;
+    switch (((const char*)ptr)[1]) {
+    case GEO_SHAPE_POINT: {
+        shape.reset(GeoPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        shape.reset(GeoLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        shape.reset(GeoPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        shape.reset(GeoMultiPoint::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        shape.reset(GeoMultiLineString::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        shape.reset(GeoMultiPolygon::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        shape.reset(GeoCollection::create_unique().release());
+        break;
+    }
+    case GEO_SHAPE_CIRCLE: {
+        shape.reset(GeoCircle::create_unique().release());
+        break;
+    }
+    default:
+        return nullptr;
+    }
+    auto res = shape->decode_from(ptr, size); //shape->decode((const char *) 
ptr + 2, size - 2);
+    if (!res) {
+        return nullptr;
+    }
+
+    //shape->decode_from(ptr,size);
+    return shape.release();
+}
+
+bool GeoShape::intersects(GeoShape* shape) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return false;
+    }
+
+    return S2BooleanOperation::Intersects(shape_index1, shape_index2);
+}
+
+bool GeoShape::ComputeArea(double* area, std::string square_unit) {
+    if (is_empty()) {
+        *area = 0;
+        return true;
+    }
+
+    std::vector<double> steradians;
+    switch (type()) {
+    case GEO_SHAPE_CIRCLE: {
+        const GeoCircle* circle = (const GeoCircle*)this;
+        steradians.emplace_back(circle->get_area());
+        break;
+    }
+    case GEO_SHAPE_POLYGON: {
+        const GeoPolygon* polygon = (const GeoPolygon*)this;
+        steradians.emplace_back(polygon->get_area());
+        break;
+    }
+    case GEO_SHAPE_POINT:
+    case GEO_SHAPE_LINE_STRING:
+    case GEO_SHAPE_MULTI_POINT:
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        *area = 0;
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            switch (collection->get_geometries_n(i)->type()) {
+            case GEO_SHAPE_POLYGON: {
+                const GeoPolygon* polygon = (const 
GeoPolygon*)collection->get_geometries_n(i);
+                steradians.emplace_back(polygon->get_area());
+                break;
+            }
+            default:
+                steradians.emplace_back(0);
+            }
+        }
+        break;
+    }
+    default:
+        return false;
+    }
+
+    if (square_unit.compare("square_meters") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareMeters(s) + *area;
+        }
+        return true;
+    } else if (square_unit.compare("square_km") == 0) {
+        for (double& s : steradians) {
+            *area = S2Earth::SteradiansToSquareKm(s) + *area;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+double GeoShape::get_length() const {
+    double length = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_LINE_STRING: {
+        return S2Earth::RadiansToMeters(((const 
GeoLineString*)this)->length());
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 1) return length;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            if ((get_geometries_n(i)->type() == GEO_SHAPE_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_MULTI_LINE_STRING ||
+                 get_geometries_n(i)->type() == GEO_SHAPE_GEOMETRY_COLLECTION) 
&&
+                !get_geometries_n(i)->is_empty()) {
+                length += get_geometries_n(i)->get_length();
+            }
+        }
+        return length;
+    }
+    default:
+        return length;
+    }
+}
+
+double GeoShape::get_perimeter() const {
+    double perimeter = 0;
+
+    switch (type()) {
+    case GEO_SHAPE_POLYGON: {
+        return S2Earth::RadiansToMeters(((const 
GeoPolygon*)this)->get_perimeter());
+    }
+    case GEO_SHAPE_MULTI_POLYGON:
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        if (get_dimension() != 2) return perimeter;
+        for (int i = 0; i < get_num_geometries(); ++i) {
+            perimeter += S2Earth::RadiansToMeters(
+                    ((const 
GeoLineString*)get_geometries_n(i))->get_perimeter());
+        }
+        return perimeter;
+    }
+    default:
+        return perimeter;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::get_centroid() const {
+    std::unique_ptr<GeoPoint> centroid = GeoPoint::create_unique();
+    if (is_empty()) {
+        centroid->set_empty();
+        return centroid;
+    }
+
+    S2Point centroid_vector(0, 0, 0);
+
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        
centroid->from_s2point(const_cast<S2Point*>(((GeoPoint*)this)->point()));
+        return centroid;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        S2Point s2_point = ((const 
GeoLineString*)this)->polyline()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_POLYGON: {
+        S2Point s2_point = ((const GeoPolygon*)this)->polygon()->GetCentroid();
+        centroid->from_s2point(&s2_point);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        std::vector<S2Point> points;
+        const GeoMultiPoint* multi_point = (const GeoMultiPoint*)this;
+        for (int i = 0; i < multi_point->get_num_point(); ++i) {
+            if (multi_point->get_point_n(i)->is_empty()) continue;
+            points.emplace_back(*multi_point->get_point_n(i)->point());
+        }
+
+        auto shape = std::make_unique<S2PointVectorShape>(points);
+        for (int j = 0; j < shape->num_edges(); j++) {
+            S2Shape::Edge e = shape->edge(j);
+            centroid_vector += e.v0;
+        }
+
+        centroid->from_s2point(&centroid_vector);
+
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        const GeoMultiLineString* multi_line_string = (const 
GeoMultiLineString*)this;
+        for (int i = 0; i < multi_line_string->get_num_line(); ++i) {
+            if (multi_line_string->get_line_string_n(i)->is_empty()) continue;
+            auto shape = std::make_unique<S2Polyline::Shape>(
+                    multi_line_string->get_line_string_n(i)->polyline());
+            for (int j = 0; j < shape->num_edges(); j++) {
+                S2Shape::Edge e = shape->edge(j);
+                centroid_vector += S2::TrueCentroid(e.v0, e.v1);
+            }
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        const GeoMultiPolygon* multi_polygon = (const GeoMultiPolygon*)this;
+        for (int i = 0; i < multi_polygon->get_num_polygon(); ++i) {
+            if (multi_polygon->get_polygon_n(i)->is_empty()) continue;
+            S2Point centroid_tmp = 
multi_polygon->get_polygon_n(i)->polygon()->GetCentroid();
+            centroid_vector += centroid_tmp;
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        const GeoCollection* collection = (const GeoCollection*)this;
+        for (int i = 0; i < collection->get_num_geometries(); ++i) {
+            GeoPoint* point = 
(GeoPoint*)collection->get_geometries_n(i)->get_centroid().release();
+            centroid_vector += *point->point();
+        }
+        centroid->from_s2point(&centroid_vector);
+        return centroid;
+    }
+    default:
+        //报错
+        return nullptr;
+    }
+}
+
+bool GeoShape::get_type_string(std::string& type_string) const {
+    switch (type()) {
+    case GEO_SHAPE_POINT: {
+        type_string = "ST_Point";
+        return true;
+    }
+    case GEO_SHAPE_LINE_STRING: {
+        type_string = "ST_LineString";
+        return true;
+    }
+    case GEO_SHAPE_POLYGON: {
+        type_string = "ST_Polygon";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POINT: {
+        type_string = "ST_MultiPoint";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_LINE_STRING: {
+        type_string = "ST_MultiLineString";
+        return true;
+    }
+    case GEO_SHAPE_MULTI_POLYGON: {
+        type_string = "ST_MultiPolygon";
+        return true;
+    }
+    case GEO_SHAPE_GEOMETRY_COLLECTION: {
+        type_string = "ST_GeometryCollection";
+        return true;
+    }
+    default:
+        return false;
+    }
+}
+
+std::unique_ptr<GeoShape> GeoShape::find_closest_point(const GeoShape* shape) 
const {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;
+
+    if (!this->add_to_s2shape_index(shape_index1) || 
!shape->add_to_s2shape_index(shape_index2)) {
+        //这里应该返回报错
+        return nullptr;
+    }
+
+    S2ClosestEdgeQuery query1(&shape_index1);
+
+    query1.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::ShapeIndexTarget target(&shape_index2);
+
+    const auto& result1 = query1.FindClosestEdge(&target);
+
+    if (result1.edge_id() == -1) {
+        //这里表示没找到最近的edge,应该返回失败,理论上不会走到这里,因为set_include_interiors(false);
+        return nullptr;
+    }
+
+    // Get the edge from index1 (edge1) that is closest to index2.
+    S2Shape::Edge edge1 = query1.GetEdge(result1);
+
+    // Now find the edge from index2 (edge2) that is closest to edge1.
+    S2ClosestEdgeQuery query2(&shape_index2);
+    query2.mutable_options()->set_include_interiors(false);
+    S2ClosestEdgeQuery::EdgeTarget target2(edge1.v0, edge1.v1);
+    auto result2 = query2.FindClosestEdge(&target2);
+
+    // what if result2 has no edges?
+    if (result2.is_interior()) {
+        //这里应该返回报错
+        return nullptr;
+        //throw Exception("S2ClosestEdgeQuery result is interior!");
+    }
+
+    S2Shape::Edge edge2 = query2.GetEdge(result2);
+
+    std::unique_ptr<GeoPoint> res_point = GeoPoint::create_unique();
+
+    S2Point s2Point = S2::GetEdgePairClosestPoints(edge1.v0, edge1.v1, 
edge2.v0, edge2.v1).first;
+    res_point->from_s2point(&s2Point);
+
+    return res_point;
+}
+
+bool GeoShape::dwithin(const GeoShape* shape, double distance) {
+    MutableS2ShapeIndex shape_index1;
+    MutableS2ShapeIndex shape_index2;

Review Comment:
   warning: method 'dwithin' can be made const 
[readability-make-member-function-const]
   
   be/src/geo/util/GeoShape.cpp:481:
   ```diff
   - thin(const GeoShape* shape, double distance) {
   + thin(const GeoShape* shape, double distance) const {
   ```
   
   be/src/geo/util/GeoShape.h:118:
   ```diff
   -     bool dwithin(const GeoShape* shape, double distance);
   +     bool dwithin(const GeoShape* shape, double distance) const;
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {

Review Comment:
   warning: function 'is_collection' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] bool is_collection() const {
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {
+        if ((type() == GEO_SHAPE_MULTI_POINT || type() == 
GEO_SHAPE_MULTI_LINE_STRING ||
+             type() == GEO_SHAPE_MULTI_POLYGON || type() == 
GEO_SHAPE_GEOMETRY_COLLECTION) &&
+            !is_empty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool is_ring() const;
+
+    bool is_empty() const { return empty; }

Review Comment:
   warning: function 'is_empty' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] bool is_empty() const { return empty; }
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {
+        if ((type() == GEO_SHAPE_MULTI_POINT || type() == 
GEO_SHAPE_MULTI_LINE_STRING ||
+             type() == GEO_SHAPE_MULTI_POLYGON || type() == 
GEO_SHAPE_GEOMETRY_COLLECTION) &&
+            !is_empty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool is_ring() const;
+
+    bool is_empty() const { return empty; }
+
+    void set_empty() { empty = true; }
+
+    [[nodiscard]] virtual int get_dimension() const = 0;
+
+    // decode from serialized data
+    static GeoShape* from_encoded(const void* data, size_t& size);
+
+    void encode_to(std::string* buf);
+
+    bool decode_from(const void* data, size_t& data_size);
+
+    // Returns the number of geometries in this collection
+    // (or 1 if this is not a collection)
+    virtual std::size_t get_num_geometries() const { return 1; }
+
+    // \brief Returns a pointer to the nth Geometry in this collection
+    // (or self if this is not a collection)
+    virtual const GeoShape* get_geometries_n(std::size_t /*n*/) const { return 
this; }
+
+    // Returns the number of point in this shape
+    [[nodiscard]] virtual std::size_t get_num_point() const { return 0; }
+
+    // try to construct a GeoShape from a WKT. If construct successfully, a 
GeoShape will
+    // be returned, and the client should delete it when don't need it.
+    // return nullptr if convert failed, and reason will be set in status
+    static GeoShape* from_wkt(const char* data, size_t size, GeoParseStatus* 
status);
+
+    virtual std::string as_wkt() const = 0;

Review Comment:
   warning: function 'as_wkt' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual std::string as_wkt() const = 0;
   ```
   



##########
be/src/geo/util/GeoShape.h:
##########
@@ -0,0 +1,135 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOSHAPE_H
+#define DORIS_GEOSHAPE_H
+
+#pragma once
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "geo/geo_common.h"
+#include "geo/wkt_parse_type.h"
+
+class MutableS2ShapeIndex;
+
+namespace doris {
+
+class GeoShape {
+public:
+    virtual ~GeoShape() = default;
+
+    virtual GeoShapeType type() const = 0;
+
+    virtual bool is_valid() const { return false; }
+
+    virtual bool is_closed() const { return false; }
+
+    bool is_collection() const {
+        if ((type() == GEO_SHAPE_MULTI_POINT || type() == 
GEO_SHAPE_MULTI_LINE_STRING ||
+             type() == GEO_SHAPE_MULTI_POLYGON || type() == 
GEO_SHAPE_GEOMETRY_COLLECTION) &&
+            !is_empty()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    bool is_ring() const;
+
+    bool is_empty() const { return empty; }
+
+    void set_empty() { empty = true; }
+
+    [[nodiscard]] virtual int get_dimension() const = 0;
+
+    // decode from serialized data
+    static GeoShape* from_encoded(const void* data, size_t& size);
+
+    void encode_to(std::string* buf);
+
+    bool decode_from(const void* data, size_t& data_size);
+
+    // Returns the number of geometries in this collection
+    // (or 1 if this is not a collection)
+    virtual std::size_t get_num_geometries() const { return 1; }
+
+    // \brief Returns a pointer to the nth Geometry in this collection
+    // (or self if this is not a collection)
+    virtual const GeoShape* get_geometries_n(std::size_t /*n*/) const { return 
this; }

Review Comment:
   warning: function 'get_geometries_n' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] virtual const GeoShape* get_geometries_n(std::size_t 
/*n*/) const { return this; }
   ```
   



##########
be/src/geo/util/GeoMultiPolygon.h:
##########
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOMULTIPOLYGON_H
+#define DORIS_GEOMULTIPOLYGON_H
+
+#include "common/factory_creator.h"
+//#include "GeoMultiLineString.h"
+#include "GeoCollection.h"
+
+namespace doris {
+
+class GeoMultiPolygon : public GeoCollection {
+    ENABLE_FACTORY_CREATOR(GeoMultiPolygon);
+
+public:
+    GeoMultiPolygon();
+    ~GeoMultiPolygon() override;
+
+    GeoShapeType type() const override { return GEO_SHAPE_MULTI_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    [[nodiscard]] GeoParseStatus from_coords(
+            const GeoCoordinateListCollections& coord_list_collections);
+
+    [[nodiscard]] std::unique_ptr<GeoCoordinateListCollections> to_coords() 
const;
+
+    // Returns the number of geometries in this collection

Review Comment:
   warning: function 'get_num_polygon' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] std::size_t get_num_polygon() const;
   ```
   



##########
be/src/geo/util/GeoMultiPolygon.h:
##########
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#ifndef DORIS_GEOMULTIPOLYGON_H
+#define DORIS_GEOMULTIPOLYGON_H
+
+#include "common/factory_creator.h"
+//#include "GeoMultiLineString.h"
+#include "GeoCollection.h"
+
+namespace doris {
+
+class GeoMultiPolygon : public GeoCollection {
+    ENABLE_FACTORY_CREATOR(GeoMultiPolygon);
+
+public:
+    GeoMultiPolygon();
+    ~GeoMultiPolygon() override;
+
+    GeoShapeType type() const override { return GEO_SHAPE_MULTI_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    [[nodiscard]] GeoParseStatus from_coords(
+            const GeoCoordinateListCollections& coord_list_collections);
+
+    [[nodiscard]] std::unique_ptr<GeoCoordinateListCollections> to_coords() 
const;
+
+    // Returns the number of geometries in this collection
+    std::size_t get_num_polygon() const;
+

Review Comment:
   warning: function 'get_polygon_n' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] GeoPolygon* get_polygon_n(std::size_t n) const;
   ```
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to