惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Recorded Future
Recorded Future
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
T
Threatpost
T
Tenable Blog
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
C
Cisco Blogs
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
A
About on SuperTechFans
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
V
V2EX
Cyberwarzone
Cyberwarzone
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
U
Unit 42
PCI Perspectives
PCI Perspectives
P
Privacy International News Feed
D
Docker

博客园 - 南水之源

osgImage和QImage互相转换 AI助手选哪个?Cowork vs OpenClaw深度解析:程序猿、打工人、老板们看过来 "数字管家"Claude Cowork,正在接管你的桌面 Claude Code:那只被称为"代码章鱼"的AI,正在吃掉整个编程世界 “拥有数字生命的龙虾”OpenClaw的前世今生 怎么领取使用国家超算中心小龙虾tokens 保存OE中使用的高程数据用gdal保存成tif文件[完成] blender GIS介绍 使用qt读取系统字体库,并进行英文名称映射 c++开发大模型mcp服务(七)使用cpp-mcp的例子MCP-ExcelAutoCpp c++开发大模型mcp服务(六)cpp-mcp库说明 c++开发大模型mcp服务(五)编译c++版本的mcp库(cpp-mcp) c++开发大模型mcp服务(四)使用工具测试高德地图的MCP(流程验证) c++开发大模型mcp服务(三)一个常规的MCP调用例子(以高德地图MCP举例) c++开发大模型mcp服务(二)MCP 架构说明 c++开发大模型mcp服务(一)目的和概念 解除360首页锁定操作 辅助Visual Studio上C++开发的工具(插件) [书]清华大学DeepSeek:从入门到精通 [原]geoserver缓存切片类GeoServerMetaTile的解析UML
使用gdal修改shp数据
南水之源 · 2025-11-19 · via 博客园 - 南水之源
#include "ShapefileEditor.h"
#include <map>
#include <cassert>
//#include <sys/stat.h>  // 用于检测文件是否存在(跨平台简易方式)
#include <stdexcept>
#include <fstream>
#include <iostream>
#include <locale>
#include <codecvt>

#ifdef _WIN32
#include <windows.h>
#endif

using namespace VRE;

// 单例实例获取
ShapefileTool& ShapefileTool::GetInstance(Encoding encoding) {
    static ShapefileTool instance(encoding);
    return instance;
}

// 私有构造函数
ShapefileTool::ShapefileTool(Encoding encoding)
    : m_dataset(nullptr), 
      m_layer(nullptr), 
      m_opened(false), 
      m_spatialRef(nullptr), 
      m_autoCalcFields(true), 
      m_encoding(encoding),
      m_lastError("") {
    InitGDAL();
    SetGDALEncoding();
}

ShapefileTool::~ShapefileTool() {
    Close();
    CleanupGDAL();
}

bool ShapefileTool::CheckFilePath(const std::string& filename)  {
    if (filename.empty()) {
        m_lastError = "文件路径为空";
        return false;
    }
    
    // 检查文件路径是否包含非法字符
    if (filename.find("..") != std::string::npos) {
        m_lastError = "文件路径包含非法字符 '..'";
        return false;
    }
    
    // 检查文件扩展名
    if (filename.length() < 4 || filename.substr(filename.length() - 4) != ".shp") {
        m_lastError = "文件扩展名必须是 .shp";
        return false;
    }
    
    return true;
}

std::string ShapefileTool::GetLastError() const {
    return m_lastError;
}

std::string ShapefileTool::ConvertFilePath(const std::string& filename) const {
#ifdef _WIN32
    // 在Windows上,GDAL 2.2.3需要GBK编码的路径
    if (m_encoding == GBK) {
        return filename; // 如果已经是GBK,直接返回
    }
    
    // 如果是UTF-8,转换为GBK
    if (m_encoding == UTF8) {
        std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
        try {
            std::wstring wstr = conv.from_bytes(filename);
            
            int size_needed = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), 
                                                nullptr, 0, nullptr, nullptr);
            std::string gbk_str(size_needed, 0);
            WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), (int)wstr.size(), 
                              &gbk_str[0], size_needed, nullptr, nullptr);
            return gbk_str;
        } catch (...) {
            // 如果转换失败,返回原路径
            return filename;
        }
    }
#endif
    // 其他平台或编码直接返回
    return filename;
}

void ShapefileTool::InitGDAL() {
    static bool initialized = false;
    if (!initialized) {
        GDALAllRegister();
        
        // 针对GDAL 2.2.3的中文路径问题,设置文件名编码为系统默认
        CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
        
        initialized = true;
    }
}

void ShapefileTool::CleanupGDAL() {
    // 注意:不要在这里调用 GDALDestroyDriverManager();
    // 因为这会影响程序中其他使用GDAL的组件
}

void ShapefileTool::SetGDALEncoding() const {
    switch (m_encoding) {
        case UTF8:
            CPLSetConfigOption("SHAPE_ENCODING", "UTF-8");
            break;
        case GBK:
            CPLSetConfigOption("SHAPE_ENCODING", "GBK");
            break;
        case SYSTEM:
        default:
            CPLSetConfigOption("SHAPE_ENCODING", "");
            break;
    }
}

std::string ShapefileTool::UTF8ToGBK(const std::string& utf8Str) const {
    if (utf8Str.empty()) return "";

    int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0);
    if (wlen == 0) return utf8Str;

    std::wstring wstr(wlen, 0);
    MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wstr[0], wlen);

    int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (len == 0) return utf8Str;

    std::string gbkStr(len, 0);
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &gbkStr[0], len, nullptr, nullptr);

    // 去除末尾的null字符
    if (!gbkStr.empty() && gbkStr[gbkStr.size() - 1] == '\0') {
        gbkStr.resize(gbkStr.size() - 1);
    }

    return gbkStr;
}

std::string ShapefileTool::GBKToUTF8(const std::string& gbkStr) const {
    if (gbkStr.empty()) return "";

    int wlen = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, nullptr, 0);
    if (wlen == 0) return gbkStr;

    std::wstring wstr(wlen, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, &wstr[0], wlen);

    int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (len == 0) return gbkStr;

    std::string utf8Str(len, 0);
    WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &utf8Str[0], len, nullptr, nullptr);

    // 去除末尾的null字符
    if (!utf8Str.empty() && utf8Str[utf8Str.size() - 1] == '\0') {
        utf8Str.resize(utf8Str.size() - 1);
    }

    return utf8Str;
}

std::string ShapefileTool::ConvertEncoding(const std::string& str) const {
    if (str.empty()) return str;

    // 根据当前编码设置进行转换
    switch (m_encoding) {
    case UTF8:
        // 如果已经是UTF-8,直接返回
        return str;

    case GBK:
#ifdef _WIN32
        // 在Windows上,将UTF-8转换为GBK
        return UTF8ToGBK(str);
#else
        // 在其他平台上,GBK可能不被支持,返回原字符串
        return str;
#endif

    case SYSTEM:
    default:
#ifdef _WIN32
        // 在Windows系统上,默认使用GBK
        return UTF8ToGBK(str);
#else
        // 在其他系统上,使用UTF-8
        return str;
#endif
    }
}

bool ShapefileTool::Open(const char* filename, bool update) {
    return Open(std::string(filename), update);
}

bool ShapefileTool::Open(const std::string& filename, bool update) {
    Close();
    
    if (!CheckFilePath(filename)) {
        return false;
    }
    
    // 设置编码
    SetGDALEncoding();
    
    // 转换文件路径编码
    std::string convertedPath = ConvertFilePath(filename);
    
    m_dataset = (GDALDataset*)GDALOpenEx(convertedPath.c_str(), 
        update ? GDAL_OF_UPDATE | GDAL_OF_VECTOR : GDAL_OF_READONLY | GDAL_OF_VECTOR, 
        nullptr, nullptr, nullptr);

    if (!m_dataset) {
        m_lastError = std::string("无法打开文件: ") + filename + ",错误: " + CPLGetLastErrorMsg();
        return false;
    }

    m_layer = m_dataset->GetLayer(0);
    if (!m_layer) {
        m_lastError = std::string("无法获取图层: ") + filename;
        Close();
        return false;
    }

    // 获取坐标系信息
    if (m_layer->GetSpatialRef()) {
        m_spatialRef = m_layer->GetSpatialRef()->Clone();
    }

    m_opened = true;
    return true;
}

bool ShapefileTool::Create(const char* filename, OGRwkbGeometryType geomType,
    const std::vector<std::pair<std::string, OGRFieldType>>& fields,
    CoordinateSystem coordSystem, bool autoCalcFields) {
    return Create(std::string(filename), geomType, fields, coordSystem, autoCalcFields);
}

bool ShapefileTool::Create(const std::string& filename, OGRwkbGeometryType geomType,
    const std::vector<std::pair<std::string, OGRFieldType>>& fields,
    CoordinateSystem coordSystem, bool autoCalcFields) {
    // 创建坐标系
    OGRSpatialReference* spatialRef = CreateSpatialReference(coordSystem);
    if (!spatialRef) {
        m_lastError = "创建坐标系失败";
        return false;
    }

    bool result = CreateWithSpatialRef(filename, geomType, fields, spatialRef, autoCalcFields);

    // 注意:CreateWithSpatialRef会接管spatialRef的内存管理
    // 如果创建失败,需要手动删除
    if (!result) {
        delete spatialRef;
    }

    return result;
}

bool ShapefileTool::CreateWithSpatialRef(const char* filename, OGRwkbGeometryType geomType,
                                        const std::vector<std::pair<std::string, OGRFieldType>>& fields,
                                        OGRSpatialReference* spatialRef,
                                        bool autoCalcFields) {
    return CreateWithSpatialRef(std::string(filename), geomType, fields, spatialRef, autoCalcFields);
}

bool ShapefileTool::CreateWithSpatialRef(const std::string& filename, OGRwkbGeometryType geomType,
                                        const std::vector<std::pair<std::string, OGRFieldType>>& fields,
                                        OGRSpatialReference* spatialRef,
                                        bool autoCalcFields) {
    Close();
    
    if (!CheckFilePath(filename)) {
        return false;
    }
    
    // 设置编码
    SetGDALEncoding();
    
    // 转换文件路径编码
    std::string convertedPath = ConvertFilePath(filename);
    
    // 获取ESRI Shapefile驱动
    GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("ESRI Shapefile");
    if (!driver) {
        m_lastError = "无法获取ESRI Shapefile驱动";
        return false;
    }
    
    // 检查驱动是否支持创建操作
    char** driverMetadata = driver->GetMetadata();
    if (!CSLFetchBoolean(driverMetadata, GDAL_DCAP_CREATE, FALSE)) {
        m_lastError = "驱动不支持创建操作";
        return false;
    }
    
    // 删除已存在文件
    CPLErr err = driver->Delete(convertedPath.c_str());
    
    // 清除错误状态
    CPLErrorReset();
    
    // 创建数据集
    m_dataset = driver->Create(convertedPath.c_str(), 0, 0, 0, GDT_Unknown, nullptr);
    if (!m_dataset) {
        m_lastError = std::string("创建数据集失败: ") + CPLGetLastErrorMsg();
        return false;
    }
    // 设置坐标系 - 克隆传入的spatialRef
    if (spatialRef) {
        m_spatialRef = spatialRef->Clone();
        if (!m_spatialRef) {
            m_lastError = "克隆空间参考系统失败";
            Close();
            return false;
        }
    } else {
        // 如果没有提供spatialRef,使用WGS84作为默认
        m_spatialRef = CreateSpatialReference(WGS84);
        if (!m_spatialRef) {
            m_lastError = "创建默认坐标系失败";
            Close();
            return false;
        }
    }
    
    m_autoCalcFields = autoCalcFields;

    // 创建图层
    m_layer = m_dataset->CreateLayer("layer", m_spatialRef, geomType, nullptr);
    if (!m_layer) {
        m_lastError = std::string("创建图层失败: ") + CPLGetLastErrorMsg();
        Close();
        return false;
    }

    // 创建字段
    for (const auto& field : fields) {
        // 转换字段名编码
        std::string encodedFieldName = ConvertEncoding(field.first);

        OGRFieldDefn fieldDefn(encodedFieldName.c_str(), field.second);
        if (m_layer->CreateField(&fieldDefn) != OGRERR_NONE) {
            m_lastError = std::string("创建字段失败: ") + field.first;
            Close();
            return false;
        }
    }

    // 自动添加几何字段
    if (m_autoCalcFields) {
        if (!AddGeometryFields(geomType)) {
            m_lastError = "添加几何字段失败";
            Close();
            return false;
        }
    }

    m_opened = true;

    // 生成.prj文件
    return CreatePrjFile(filename.c_str());
}

int ShapefileTool::GetFeatureCount() {
    if (!m_opened || !m_layer) return 0;
    return (int)m_layer->GetFeatureCount();
}

OGRFeature* ShapefileTool::GetFeature(int id) {
    if (!m_opened || !m_layer) return nullptr;
    return m_layer->GetFeature(id);
}

bool ShapefileTool::SetGeometry(int id, OGRGeometry* geometry) {
    if (!m_opened || !m_layer) {
        if (geometry) OGRGeometryFactory::destroyGeometry(geometry);
        return false;
    }

    OGRFeature* feature = m_layer->GetFeature(id);
    if (!feature) {
        if (geometry) OGRGeometryFactory::destroyGeometry(geometry);
        return false;
    }

    OGRErr err = feature->SetGeometry(geometry);
    if (err != OGRERR_NONE) {
        OGRFeature::DestroyFeature(feature);
        if (geometry) OGRGeometryFactory::destroyGeometry(geometry);
        return false;
    }

    // 自动计算几何字段
    if (m_autoCalcFields) {
        CalculateAndSetGeometryFields(feature, geometry);
    }

    bool result = (m_layer->SetFeature(feature) == OGRERR_NONE);
    OGRFeature::DestroyFeature(feature);

    // 几何对象由OGRFeature接管,不需要手动销毁
    return result;
}

bool ShapefileTool::SetField(int id, const char* fieldName, const char* value) {
    return SetField(id, fieldName, std::string(value));
}

bool ShapefileTool::SetField(int id, const char* fieldName, const std::string& value) {
    if (!m_opened || !m_layer) return false;

    OGRFeature* feature = m_layer->GetFeature(id);
    if (!feature) return false;

    // 转换编码
    std::string encodedValue = ConvertEncoding(value);
    feature->SetField(fieldName, encodedValue.c_str());

    bool result = (m_layer->SetFeature(feature) == OGRERR_NONE);
    OGRFeature::DestroyFeature(feature);
    return result;
}

bool ShapefileTool::SetField(int id, const char* fieldName, int value) {
    if (!m_opened || !m_layer) return false;

    OGRFeature* feature = m_layer->GetFeature(id);
    if (!feature) return false;

    feature->SetField(fieldName, value);
    bool result = (m_layer->SetFeature(feature) == OGRERR_NONE);
    OGRFeature::DestroyFeature(feature);
    return result;
}

bool ShapefileTool::SetField(int id, const char* fieldName, double value) {
    if (!m_opened || !m_layer) return false;

    OGRFeature* feature = m_layer->GetFeature(id);
    if (!feature) return false;

    feature->SetField(fieldName, value);
    bool result = (m_layer->SetFeature(feature) == OGRERR_NONE);
    OGRFeature::DestroyFeature(feature);
    return result;
}

int ShapefileTool::AddFeature(OGRGeometry* geometry,
    const std::vector<std::pair<std::string, std::string>>& attributes) 
{
    if (!m_opened || !m_layer) {
        if (geometry) OGRGeometryFactory::destroyGeometry(geometry);
        return -1;
    }

    OGRFeature* feature = OGRFeature::CreateFeature(m_layer->GetLayerDefn());
    if (!feature) {
        if (geometry) OGRGeometryFactory::destroyGeometry(geometry);
        return -1;
    }

    // 设置几何
    if (geometry) {
        OGRErr err = feature->SetGeometry(geometry);
        if (err != OGRERR_NONE) {
            OGRFeature::DestroyFeature(feature);
            OGRGeometryFactory::destroyGeometry(geometry);
            return -1;
        }
    }

    // 设置属性 - 这里需要确保编码转换
    for (const auto& attr : attributes) {
        // 转换编码
        std::string encodedValue = ConvertEncoding(attr.second);
        feature->SetField(attr.first.c_str(), encodedValue.c_str());
    }

    // 自动计算几何字段
    if (m_autoCalcFields && geometry) {
        CalculateAndSetGeometryFields(feature, geometry);
    }

    // 添加要素
    if (m_layer->CreateFeature(feature) != OGRERR_NONE) {
        OGRFeature::DestroyFeature(feature);
        return -1;
    }

    int fid = (int)feature->GetFID();
    OGRFeature::DestroyFeature(feature);
    return fid;
}

bool ShapefileTool::CopyAttributes(int sourceId, int targetId) {
    if (!m_opened || !m_layer) return false;

    OGRFeature* sourceFeature = m_layer->GetFeature(sourceId);
    OGRFeature* targetFeature = m_layer->GetFeature(targetId);

    if (!sourceFeature || !targetFeature) {
        if (sourceFeature) OGRFeature::DestroyFeature(sourceFeature);
        if (targetFeature) OGRFeature::DestroyFeature(targetFeature);
        return false;
    }

    // 复制所有属性字段
    int fieldCount = sourceFeature->GetFieldCount();
    for (int i = 0; i < fieldCount; i++) {
        OGRFieldDefn* fieldDefn = sourceFeature->GetFieldDefnRef(i);
        if (fieldDefn) {
            switch (fieldDefn->GetType()) {
            case OFTInteger:
                targetFeature->SetField(i, sourceFeature->GetFieldAsInteger(i));
                break;
            case OFTReal:
                targetFeature->SetField(i, sourceFeature->GetFieldAsDouble(i));
                break;
            case OFTString:
            default:
                // 对于字符串字段,获取原始值并重新设置(确保编码正确)
                const char* strValue = sourceFeature->GetFieldAsString(i);
                if (strValue) {
                    std::string encodedValue = ConvertEncoding(strValue);
                    targetFeature->SetField(i, encodedValue.c_str());
                }
                break;
            }
        }
    }

    bool result = (m_layer->SetFeature(targetFeature) == OGRERR_NONE);

    OGRFeature::DestroyFeature(sourceFeature);
    OGRFeature::DestroyFeature(targetFeature);
    return result;
}

bool ShapefileTool::Save() {
    if (!m_opened || !m_dataset) return false;
    GDALFlushCache(m_dataset);
    return true;
}

void ShapefileTool::Close() {
    if (m_dataset) {
        GDALClose(m_dataset);
        m_dataset = nullptr;
        m_layer = nullptr;
    }
    m_opened = false;
}

OGRPoint* ShapefileTool::CreatePoint(const SVREVector3& point) {
    return new OGRPoint(point.lon, point.lat, point.alt);
}

OGRLineString* ShapefileTool::CreateLineString(const VVREGeoPoint& points) {
    if (points.empty()) return nullptr;

    OGRLineString* line = new OGRLineString();
    for (const auto& point : points) {
        line->addPoint(point.lon, point.lat, point.alt);
    }
    return line;
}

OGRPolygon* ShapefileTool::CreatePolygon(const std::vector<VVREGeoPoint>& rings) {
    if (rings.empty()) return nullptr;

    OGRPolygon* polygon = new OGRPolygon();

    for (size_t i = 0; i < rings.size(); i++) {
        const auto& ringPoints = rings[i];
        if (ringPoints.size() < 3) {
            delete polygon;
            return nullptr;
        }

        OGRLinearRing* ring = new OGRLinearRing();
        for (const auto& point : ringPoints) {
            ring->addPoint(point.lon, point.lat, point.alt);
        }

        // 闭合环(如果首尾不相等)
        if (ring->getNumPoints() > 0) {
            OGRPoint first, last;
            ring->getPoint(0, &first);
            ring->getPoint(ring->getNumPoints() - 1, &last);
            if (first.getX() != last.getX() || first.getY() != last.getY() || first.getZ() != last.getZ()) {
                ring->addPoint(first.getX(), first.getY(), first.getZ());
            }
        }

        if (i == 0) {
            polygon->addRingDirectly(ring);  // 外环
        } else {
            polygon->addRing(ring);  // 内环
        }
    }

    return polygon;
}

SVREVector3 ShapefileTool::ConvertToVVREPoint(OGRGeometry* geometry) {
    SVREVector3 point;
    if (!geometry) return point;

    OGRPoint* ogrPoint = dynamic_cast<OGRPoint*>(geometry);
    if (ogrPoint) {
        point.lon = ogrPoint->getX();
        point.lat = ogrPoint->getY();
        point.alt = ogrPoint->getZ();
    }
    return point;
}

VVREGeoPoint ShapefileTool::ConvertToVVRELineString(OGRGeometry* geometry) {
    VVREGeoPoint points;
    if (!geometry) return points;

    OGRLineString* lineString = dynamic_cast<OGRLineString*>(geometry);
    if (lineString) {
        int pointCount = lineString->getNumPoints();
        for (int i = 0; i < pointCount; i++) {
            OGRPoint point;
            lineString->getPoint(i, &point);
            points.push_back(SVREVector3(point.getX(), point.getY(), point.getZ()));
        }
    }
    return points;
}

std::vector<VVREGeoPoint> ShapefileTool::ConvertToVVREPolygon(OGRGeometry* geometry) {
    std::vector<VVREGeoPoint> rings;
    if (!geometry) return rings;

    OGRPolygon* polygon = dynamic_cast<OGRPolygon*>(geometry);
    if (polygon) {
        // 外环
        OGRLinearRing* exteriorRing = polygon->getExteriorRing();
        if (exteriorRing) {
            VVREGeoPoint exteriorPoints;
            int pointCount = exteriorRing->getNumPoints();
            for (int i = 0; i < pointCount; i++) {
                OGRPoint point;
                exteriorRing->getPoint(i, &point);
                exteriorPoints.push_back(SVREVector3(point.getX(), point.getY(), point.getZ()));
            }
            rings.push_back(exteriorPoints);
        }

        // 内环
        int interiorRingCount = polygon->getNumInteriorRings();
        for (int i = 0; i < interiorRingCount; i++) {
            OGRLinearRing* interiorRing = polygon->getInteriorRing(i);
            if (interiorRing) {
                VVREGeoPoint interiorPoints;
                int pointCount = interiorRing->getNumPoints();
                for (int j = 0; j < pointCount; j++) {
                    OGRPoint point;
                    interiorRing->getPoint(j, &point);
                    interiorPoints.push_back(SVREVector3(point.getX(), point.getY(), point.getZ()));
                }
                rings.push_back(interiorPoints);
            }
        }
    }
    return rings;
}

bool ShapefileTool::SetCoordinateSystem(CoordinateSystem coordSystem) {
    if (!m_opened || !m_layer) return false;

    OGRSpatialReference* spatialRef = CreateSpatialReference(coordSystem);
    if (!spatialRef) return false;

    // 设置图层的空间参考
    if (m_layer->GetSpatialRef()) {
        delete m_spatialRef;
    }
    m_spatialRef = spatialRef;

    // 重新生成.prj文件
    if (m_dataset) {
        const char* filename = m_dataset->GetDescription();
        return CreatePrjFile(filename);
    }

    return false;
}

bool ShapefileTool::SetSpatialReference(OGRSpatialReference* spatialRef) {
    if (!m_opened || !m_layer || !spatialRef) return false;

    if (m_spatialRef) {
        delete m_spatialRef;
    }
    m_spatialRef = spatialRef->Clone();

    // 重新生成.prj文件
    if (m_dataset) {
        const char* filename = m_dataset->GetDescription();
        return CreatePrjFile(filename);
    }

    return false;
}

std::string ShapefileTool::GetProjectionWKT() {
    if (!m_spatialRef) return "";

    char* wkt = nullptr;
    m_spatialRef->exportToWkt(&wkt);
    if (wkt) {
        std::string result(wkt);
        CPLFree(wkt);
        return result;
    }
    return "";
}

OGRSpatialReference* ShapefileTool::CreateSpatialReference(CoordinateSystem coordSystem) {
    OGRSpatialReference* spatialRef = new OGRSpatialReference();

    switch (coordSystem) {
    case WGS84:
        spatialRef->SetWellKnownGeogCS("WGS84");
        break;
    case WebMercator:
        spatialRef->importFromEPSG(3857);  // Web Mercator
        break;
    case UTM_WGS84_50N:
        spatialRef->importFromEPSG(32650);  // UTM Zone 50N, WGS84
        break;
    default:
        delete spatialRef;
        return nullptr;
    }

    return spatialRef;
}

bool ShapefileTool::CreatePrjFile(const char* filename) {
    if (!m_spatialRef) return false;

    // 生成.prj文件路径
    std::string prjFilename = filename;
    size_t dotPos = prjFilename.find_last_of('.');
    if (dotPos != std::string::npos) {
        prjFilename = prjFilename.substr(0, dotPos);
    }
    prjFilename += ".prj";

    // 转换文件路径编码
    std::string convertedPrjPath = ConvertFilePath(prjFilename);

    // 导出为WKT格式
    char* wkt = nullptr;
    m_spatialRef->exportToWkt(&wkt);
    if (!wkt) {
        return false;
    }

    // 写入.prj文件
    std::ofstream prjFile(convertedPrjPath, std::ios::binary);
    if (!prjFile.is_open()) {
        CPLFree(wkt);
        return false;
    }

    prjFile << wkt;
    prjFile.close();

    CPLFree(wkt);
    return true;
}

bool ShapefileTool::AddGeometryFields(OGRwkbGeometryType geomType) {
    if (!m_layer) return false;

    // 根据几何类型添加相应的字段
    switch (wkbFlatten(geomType)) {
    case wkbLineString:
    case wkbMultiLineString: {
        // 为线数据添加长度字段
        OGRFieldDefn lengthField("Length", OFTReal);
        lengthField.SetWidth(12);
        lengthField.SetPrecision(2);
        if (m_layer->CreateField(&lengthField) != OGRERR_NONE) {
            return false;
        }
        break;
    }
    case wkbPolygon:
    case wkbMultiPolygon: {
        // 为面数据添加面积字段
        OGRFieldDefn areaField("Area", OFTReal);
        areaField.SetWidth(15);
        areaField.SetPrecision(2);
        if (m_layer->CreateField(&areaField) != OGRERR_NONE) {
            return false;
        }
        break;
    }
    default:
        // 点数据不需要特殊字段
        break;
    }

    return true;
}

bool ShapefileTool::CalculateAndSetGeometryFields(OGRFeature* feature, OGRGeometry* geometry) {
    if (!feature || !geometry) return false;

    OGRwkbGeometryType geomType = wkbFlatten(geometry->getGeometryType());

    switch (geomType) {
    case wkbLineString:
    case wkbMultiLineString: {
        // 计算线长度
        double length = CalculateGeodesicLength(geometry);
        int fieldIndex = feature->GetFieldIndex("Length");
        if (fieldIndex >= 0) {
            feature->SetField(fieldIndex, length);
        }
        break;
    }
    case wkbPolygon:
    case wkbMultiPolygon: {
        // 计算面面积
        double area = CalculateGeodesicArea(geometry);
        int fieldIndex = feature->GetFieldIndex("Area");
        if (fieldIndex >= 0) {
            feature->SetField(fieldIndex, area);
        }
        break;
    }
    default:
        break;
    }

    return true;
}

double ShapefileTool::CalculateGeodesicLength(OGRGeometry* geometry) {
    if (!geometry) return 0.0;

    double totalLength = 0.0;

    // 处理不同类型的线几何
    OGRwkbGeometryType geomType = wkbFlatten(geometry->getGeometryType());

    if (geomType == wkbLineString) {
        OGRLineString* line = (OGRLineString*)geometry;

        // 创建用于测地线计算的几何对象
        OGRGeometry* geodesicGeometry = line->clone();
        if (geodesicGeometry) {
            // 如果是在地理坐标系中,使用测地线计算
            if (m_spatialRef && m_spatialRef->IsGeographic()) {
                // 转换为测地线长度(米)
                totalLength = line->get_Length();

                // 对于地理坐标系,需要将度转换为米(近似)
                // 这里使用赤道处1度≈111.32km的近似值
                // 实际应用中可以使用更精确的椭球体计算方法
                totalLength *= 111320.0; // 1度 ≈ 111.32km
            }
            else {
                // 投影坐标系直接使用长度
                totalLength = line->get_Length();
            }
            OGRGeometryFactory::destroyGeometry(geodesicGeometry);
        }
    }
    else if (geomType == wkbMultiLineString) {
        OGRMultiLineString* multiLine = (OGRMultiLineString*)geometry;
        for (int i = 0; i < multiLine->getNumGeometries(); i++) {
            totalLength += CalculateGeodesicLength(multiLine->getGeometryRef(i));
        }
    }

    return totalLength;
}

double ShapefileTool::CalculateGeodesicArea(OGRGeometry* geometry) {
    if (!geometry) return 0.0;

    double totalArea = 0.0;

    // 处理不同类型的面几何
    OGRwkbGeometryType geomType = wkbFlatten(geometry->getGeometryType());

    if (geomType == wkbPolygon) {
        OGRPolygon* polygon = (OGRPolygon*)geometry;

        // 创建用于测地线计算的几何对象
        OGRGeometry* geodesicGeometry = polygon->clone();
        if (geodesicGeometry) {
            // 如果是在地理坐标系中,使用测地线计算
            if (m_spatialRef && m_spatialRef->IsGeographic()) {
                // 转换为测地线面积(平方米)
                totalArea = polygon->get_Area();

                // 对于地理坐标系,需要将平方度转换为平方米(近似)
                // 这里使用赤道处1平方度≈12,355km²的近似值
                // 实际应用中可以使用更精确的椭球体计算方法
                totalArea *= 12355000000.0; // 1平方度 ≈ 12,355km²
            }
            else {
                // 投影坐标系直接使用面积
                totalArea = polygon->get_Area();
            }
            OGRGeometryFactory::destroyGeometry(geodesicGeometry);
        }
    }
    else if (geomType == wkbMultiPolygon) {
        OGRMultiPolygon* multiPolygon = (OGRMultiPolygon*)geometry;
        for (int i = 0; i < multiPolygon->getNumGeometries(); i++) {
            totalArea += CalculateGeodesicArea(multiPolygon->getGeometryRef(i));
        }
    }

    return totalArea;
}

bool ShapefileTool::RecalculateGeometryFields() {
    if (!m_opened || !m_layer || !m_autoCalcFields) return false;

    // 重置读取位置
    m_layer->ResetReading();

    OGRFeature* feature;
    bool success = true;

    // 遍历所有要素并重新计算几何字段
    while ((feature = m_layer->GetNextFeature()) != nullptr) {
        OGRGeometry* geometry = feature->GetGeometryRef();
        if (geometry) {
            if (!CalculateAndSetGeometryFields(feature, geometry)) {
                success = false;
            }

            // 更新要素
            if (m_layer->SetFeature(feature) != OGRERR_NONE) {
                success = false;
            }
        }

        OGRFeature::DestroyFeature(feature);
    }

    return success;
}

void ShapefileTool::SetEncoding(Encoding encoding) {
    m_encoding = encoding;
    SetGDALEncoding();
}

ShapefileTool::Encoding ShapefileTool::GetEncoding() const {
    return m_encoding;
}