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


##########
be/src/geo/util/GeoPoint.h:
##########
@@ -0,0 +1,98 @@
+// 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_GEOPOINT_H
+#define DORIS_GEOPOINT_H
+
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+template <typename T>
+class Vector3;
+class S2Shape;
+using S2Point = Vector3<double>;
+
+namespace doris {
+
+class GeoPoint : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPoint);
+
+public:
+    GeoPoint();
+    ~GeoPoint() override;
+
+    static void print_s2point(std::ostream& os, const S2Point& point);
+
+    static GeoParseStatus to_s2point(double lng, double lat, S2Point* point);
+    static GeoParseStatus to_s2point(const GeoCoordinate& coord, S2Point* 
point);
+
+    GeoParseStatus from_coord(double x, double y);
+    GeoParseStatus from_coord(const GeoCoordinate& point);
+
+    GeoParseStatus from_s2point(S2Point* point);
+
+    GeoCoordinates to_coords() const;
+
+    std::unique_ptr<GeoCoordinate> to_coord() const;
+
+    GeoShapeType type() const override { return GEO_SHAPE_POINT; }
+
+    bool is_valid() const override;
+
+    bool is_closed() const override { return !is_empty(); }
+
+    [[nodiscard]] int get_dimension() const override { return 0; }
+
+    [[nodiscard]] const S2Point* point() const { return _point.get(); }
+
+    [[nodiscard]] std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static bool ComputeDistance(double x_lng, double x_lat, double y_lng, 
double y_lat,
+                                double* distance);
+
+    static bool ComputeAngleSphere(double x_lng, double x_lat, double y_lng, 
double y_lat,
+                                   double* angle);
+    static bool ComputeAngle(GeoPoint* p1, GeoPoint* p2, GeoPoint* p3, double* 
angle);
+    static bool ComputeAzimuth(GeoPoint* p1, GeoPoint* p2, double* angle);
+
+    std::string as_wkt() const override;
+
+    [[nodiscard]] std::size_t get_num_point() const override { return 1; }
+
+    std::unique_ptr<GeoShape> boundary() const override;
+
+    bool add_to_s2shape_index(MutableS2ShapeIndex& S2shape_index) const 
override;
+
+    //void add_to_s2point_index(S2PointIndex<int>& S2point_index, int i);
+
+    double x() const;
+    double y() const;

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



##########
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]);
+        multi_linestring->add_one_geometry(linestring.release());
+    }
+
+    return multi_linestring;
+}
+
+bool GeoPolygon::add_to_s2shape_index(MutableS2ShapeIndex& S2shape_index) 
const {
+    if (is_empty() || !is_valid()) return false;

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
       if (is_empty() || !is_valid()) { return false;
   }
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;

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



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static void print_coords(std::ostream& os, const GeoPolygon& polygon);
+    std::string as_wkt() const override;
+
+    int num_loops() const;
+    double get_area() const;

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



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static void print_coords(std::ostream& os, const GeoPolygon& polygon);
+    std::string as_wkt() const override;
+
+    int num_loops() const;

Review Comment:
   warning: function 'num_loops' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] int num_loops() 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();

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   n(i)->is_empty()) { continue;
   }
   ```
   



##########
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());

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   n(i)->is_empty()) { continue;
   }
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }

Review Comment:
   warning: function 'polygon' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] const S2Polygon* polygon() const { return _polygon.get(); }
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;

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



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H

Review Comment:
   warning: macro is not used [clang-diagnostic-unused-macros]
   ```cpp
   #define DORIS_GEOPOLYGON_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]) {

Review Comment:
   warning: ISO C++20 considers use of overloaded operator '!=' (with operand 
types '__gnu_cxx::__alloc_traits<std::allocator<Vector3<double>>, 
Vector3<double>>::value_type' (aka 'Vector3<double>') and 
'__gnu_cxx::__alloc_traits<std::allocator<Vector3<double>>, 
Vector3<double>>::value_type') to be ambiguous despite there being a unique 
best viable function with non-reversed arguments 
[clang-diagnostic-ambiguous-reversed-operator]
   ```cpp
           if ((*points)[rhs] != (*points)[lhs]) {
                              ^
   ```
   <details>
   <summary>Additional context</summary>
   
   **thirdparty/installed/include/s2/util/math/vector.h:104:** candidate 
function with non-reversed arguments
   ```cpp
     bool operator!=(const D& b) const { return !(AsD() == b); }
          ^
   ```
   **thirdparty/installed/include/s2/util/math/vector.h:100:** ambiguous 
candidate function with reversed arguments
   ```cpp
     bool operator==(const D& b) const {
          ^
   ```
   
   </details>
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;

Review Comment:
   warning: function 'to_coords' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] const std::unique_ptr<GeoCoordinateLists> to_coords() 
const;
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;

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



##########
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]) {

Review Comment:
   warning: ISO C++20 considers use of overloaded operator '!=' (with operand 
types 'const __gnu_cxx::__alloc_traits<std::allocator<Vector3<double>>, 
Vector3<double>>::value_type' (aka 'const Vector3<double>') and 'const 
__gnu_cxx::__alloc_traits<std::allocator<Vector3<double>>, 
Vector3<double>>::value_type') to be ambiguous despite there being a unique 
best viable function with non-reversed arguments 
[clang-diagnostic-ambiguous-reversed-operator]
   ```cpp
       if (points[0] != points[points.size() - 1]) {
                     ^
   ```
   <details>
   <summary>Additional context</summary>
   
   **thirdparty/installed/include/s2/util/math/vector.h:104:** candidate 
function with non-reversed arguments
   ```cpp
     bool operator!=(const D& b) const { return !(AsD() == b); }
          ^
   ```
   **thirdparty/installed/include/s2/util/math/vector.h:100:** ambiguous 
candidate function with reversed arguments
   ```cpp
     bool operator==(const D& b) const {
          ^
   ```
   
   </details>
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static void print_coords(std::ostream& os, const GeoPolygon& polygon);
+    std::string as_wkt() const override;
+
+    int num_loops() const;
+    double get_area() const;
+    S2Loop* get_loop(int i) const;

Review Comment:
   warning: function 'get_loop' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] S2Loop* get_loop(int i) const;
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }

Review Comment:
   warning: function 'type' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] GeoShapeType type() const override { return 
GEO_SHAPE_POLYGON; }
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;

Review Comment:
   warning: function 'get_s2shape' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] std::unique_ptr<S2Shape> get_s2shape() const;
   ```
   



##########
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;

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
       if (is_empty()) { return 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) {

Review Comment:
   warning: method 'intersects' can be made const 
[readability-make-member-function-const]
   
   be/src/geo/util/GeoShape.cpp:198:
   ```diff
   - e* shape) {
   + e* shape) const {
   ```
   
   be/src/geo/util/GeoShape.h:98:
   ```diff
   -     bool intersects(GeoShape* shape);
   +     bool intersects(GeoShape* shape) const;
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static void print_coords(std::ostream& os, const GeoPolygon& polygon);
+    std::string as_wkt() const override;

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



##########
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) {

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   sion() != 1) { return length;
   }
   ```
   



##########
be/src/geo/util/GeoPolygon.h:
##########
@@ -0,0 +1,86 @@
+// 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_GEOPOLYGON_H
+#define DORIS_GEOPOLYGON_H
+
+#include "GeoLineString.h"
+#include "GeoPoint.h"
+#include "GeoShape.h"
+#include "common/factory_creator.h"
+#include "geo/wkt_parse_type.h"
+
+class S2Polygon;
+class S2Loop;
+
+namespace doris {
+class GeoPolygon : public GeoShape {
+    ENABLE_FACTORY_CREATOR(GeoPolygon);
+
+public:
+    GeoPolygon();
+    ~GeoPolygon() override;
+
+    bool is_valid() const override;
+
+    bool is_closed() const override;
+
+    static GeoParseStatus to_s2loop(const GeoCoordinates& coords, 
std::unique_ptr<S2Loop>* loop);
+
+    GeoParseStatus from_coords(const GeoCoordinateLists& coords_list);
+    const std::unique_ptr<GeoCoordinateLists> to_coords() const;
+
+    GeoParseStatus from_s2loop(std::vector<std::unique_ptr<S2Loop>>& loops);
+
+    GeoParseStatus from_s2polygon(std::unique_ptr<S2Polygon> s2polygon);
+
+    GeoShapeType type() const override { return GEO_SHAPE_POLYGON; }
+
+    [[nodiscard]] int get_dimension() const override { return 2; }
+
+    double get_perimeter() const;
+
+    const S2Polygon* polygon() const { return _polygon.get(); }
+
+    std::unique_ptr<S2Shape> get_s2shape() const;
+
+    bool contains(const GeoShape* rhs) const override;
+
+    static void print_coords(std::ostream& os, const GeoPolygon& polygon);
+    std::string as_wkt() const override;
+
+    int num_loops() const;
+    double get_area() const;
+    S2Loop* get_loop(int i) const;
+
+    [[nodiscard]] std::size_t get_num_point() const override;
+
+    std::unique_ptr<GeoShape> boundary() const override;

Review Comment:
   warning: function 'boundary' should be marked [[nodiscard]] 
[modernize-use-nodiscard]
   
   ```suggestion
       [[nodiscard]] std::unique_ptr<GeoShape> boundary() const override;
   ```
   



##########
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) {

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   n() != 2) { return perimeter;
   }
   ```
   



##########
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) {

Review Comment:
   warning: method 'find_closest_point' can be made const 
[readability-make-member-function-const]
   
   be/src/geo/util/GeoShape.cpp:431:
   ```diff
   - _point(const GeoShape* shape) {
   + _point(const GeoShape* shape) const {
   ```
   
   be/src/geo/util/GeoShape.h:116:
   ```diff
   -     std::unique_ptr<GeoShape> find_closest_point(const GeoShape* shape);
   +     std::unique_ptr<GeoShape> find_closest_point(const GeoShape* shape) 
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>(

Review Comment:
   warning: statement should be inside braces 
[readability-braces-around-statements]
   
   ```suggestion
   n(i)->is_empty()) { continue;
   }
   ```
   



-- 
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