You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

311 lines
12 KiB
C++

1 month ago
#include "StdAfx.h"
#include "GenerateSEC.h"
#include <cmath>
#include <algorithm>
#include <limits>
// --- GEOS <20><><EFBFBD><EFBFBD><EFBFBD>Ĺ<EFBFBD><C4B9><EFBFBD> ---
void geos_message_handler(const char* fmt, ...) { /* <20><><EFBFBD><EFBFBD>֪ͨ */ }
class GEOSContext {
public:
GEOSContext() { handle = initGEOS_r(geos_message_handler, geos_message_handler); }
~GEOSContext() { finishGEOS_r(handle); }
GEOSContextHandle_t handle;
};
static GEOSContext g_geos;
// --- <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---
inline double Round6(double v) { return std::floor(v * 1e6 + 0.5) / 1e6; }
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȸ<EFBFBD><EFBFBD><EFBFBD> Python export_to_csv_single_line
* 1. <EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD> Shell (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ׶<EFBFBD><EFBFBD>ĵ<EFBFBD>)
* 2. 6λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* 3. <EFBFBD>ϸ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static std::vector<CPoint2D> GEOSPolygonToSingleLine(const GEOSGeometry* poly) {
GEOSContextHandle_t h = g_geos.handle;
if (!poly || GEOSGeomTypeId_r(h, poly) != GEOS_POLYGON) return {};
auto extract_ring = [&](const GEOSGeometry* ring) {
const GEOSCoordSequence* seq = GEOSGeom_getCoordSeq_r(h, ring);
uint32_t size;
GEOSCoordSeq_getSize_r(h, seq, &size);
std::vector<CPoint2D> pts;
for (uint32_t i = 0; i < size - 1; ++i) { // [:-1] <20>Ƴ<EFBFBD><C6B3>պϵ<D5BA>
double x, y;
GEOSCoordSeq_getXY_r(h, seq, i, &x, &y);
pts.push_back({ x, y });
}
return pts;
};
// 1. <20><>ȡ<EFBFBD><C8A1>ʼ<EFBFBD>
std::vector<CPoint2D> shell = extract_ring(GEOSGetExteriorRing_r(h, poly));
// 2. <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD>
int num_holes = GEOSGetNumInteriorRings_r(h, poly);
std::vector<std::vector<CPoint2D>> holes;
for (int i = 0; i < num_holes; ++i) {
holes.push_back(extract_ring(GEOSGetInteriorRingN_r(h, poly, i)));
}
// 3. ̰<><CCB0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD>
while (!holes.empty()) {
double min_d2 = (std::numeric_limits<double>::max)();
int best_hole_idx = -1;
size_t best_s = 0, best_h = 0;
for (int i = 0; i < (int)holes.size(); ++i) {
const auto& hole = holes[i];
for (size_t s_idx = 0; s_idx < shell.size(); ++s_idx) {
double sx = Round6(shell[s_idx].x0);
double sy = Round6(shell[s_idx].y0);
for (size_t h_idx = 0; h_idx < hole.size(); ++h_idx) {
double hx = Round6(hole[h_idx].x0);
double hy = Round6(hole[h_idx].y0);
double d2 = (sx - hx) * (sx - hx) + (sy - hy) * (sy - hy);
// <20>ϸ<EFBFBD>С<EFBFBD>ڣ<EFBFBD>ģ<EFBFBD><C4A3> np.argmin <20>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD>
if (d2 < min_d2 - 1e-12) {
min_d2 = d2;
best_hole_idx = i;
best_s = s_idx;
best_h = h_idx;
}
}
}
}
// 4. ִ<><D6B4>ƴ<EFBFBD><C6B4>
std::vector<CPoint2D> target_hole = holes[best_hole_idx];
holes.erase(holes.begin() + best_hole_idx);
CPoint2D conn_shell = shell[best_s];
CPoint2D conn_hole = target_hole[best_h];
std::vector<CPoint2D> next_shell;
next_shell.reserve(shell.size() + target_hole.size() + 2);
for (size_t i = 0; i <= best_s; ++i) next_shell.push_back(shell[i]);
for (size_t i = 0; i < target_hole.size(); ++i) {
next_shell.push_back(target_hole[(best_h + i) % target_hole.size()]);
}
next_shell.push_back(conn_hole);
next_shell.push_back(conn_shell);
for (size_t i = best_s + 1; i < shell.size(); ++i) next_shell.push_back(shell[i]);
shell = next_shell; // <20><><EFBFBD><EFBFBD> shell
}
if (!shell.empty()) shell.push_back(shell[0]); // <20><><EFBFBD>󲹻رպϵ<D5BA>
return shell;
}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Python _generate_base_shapes
*/
static GEOSGeometry* InternalGenerateBase(const std::vector<CPoint2D>& wells, double w, double h, double ang, double gap) {
GEOSContextHandle_t handle = g_geos.handle;
std::vector<GEOSGeometry*> polys;
double rad = ang * 3.14159265358979 / 180.0;
for (const auto& well : wells) {
GEOSCoordSequence* seq = GEOSCoordSeq_create_r(handle, 5, 2);
double dx[] = { -w / 2, w / 2, w / 2, -w / 2, -w / 2 };
double dy[] = { -h / 2, -h / 2, h / 2, h / 2, -h / 2 };
for (int i = 0; i < 5; ++i) {
double rx = dx[i] * cos(rad) - dy[i] * sin(rad);
double ry = dx[i] * sin(rad) + dy[i] * cos(rad);
GEOSCoordSeq_setXY_r(handle, seq, i, well.x0 + rx, well.y0 + ry);
}
GEOSGeometry* ring = GEOSGeom_createLinearRing_r(handle, seq);
polys.push_back(GEOSGeom_createPolygon_r(handle, ring, nullptr, 0));
}
// 1. Unary Union (<28><>Ӧ Python unary_union)
GEOSGeometry* coll = GEOSGeom_createCollection_r(handle, GEOS_MULTIPOLYGON, polys.data(), (uint32_t)polys.size());
GEOSGeometry* merged = GEOSUnaryUnion_r(handle, coll);
// 2. Simplify (<28><>Ӧ Python simplify(0.01))
GEOSGeometry* simplified = GEOSSimplify_r(handle, merged, 0.01);
GEOSGeom_destroy_r(handle, merged);
// 3. Gap Buffer (б<>Ӳ<EFBFBD><D3B2><EFBFBD>)
if (gap > 0.01) {
GEOSBufferParams* params = GEOSBufferParams_create_r(handle);
GEOSBufferParams_setJoinStyle_r(handle, params, GEOSBUF_JOIN_MITRE);
GEOSBufferParams_setMitreLimit_r(handle, params, 5.0);
GEOSGeometry* temp = GEOSBufferWithParams_r(handle, simplified, params, gap / 2.0);
GEOSGeom_destroy_r(handle, simplified);
simplified = GEOSBufferWithParams_r(handle, temp, params, -gap / 2.0);
GEOSGeom_destroy_r(handle, temp);
GEOSBufferParams_destroy_r(handle, params);
}
return simplified;
}
NItem::GenerateSECReserve::GenerateSECReserve()
{
}
NItem::GenerateSECReserve::~GenerateSECReserve()
{
}
std::vector<std::vector<CPoint2D>> NItem::GenerateSECReserve::CalculatePDP(
const std::vector<CPoint2D>& wells, double width, double height, double angle_deg, double gap,
const std::vector<CPoint2D>& boundaryPoints, bool useClip)
{
GEOSContextHandle_t h = g_geos.handle;
GEOSGeometry* pdp = InternalGenerateBase(wells, width, height, angle_deg, gap);
if (useClip && boundaryPoints.size() >= 3) {
GEOSCoordSequence* seq = GEOSCoordSeq_create_r(h, (uint32_t)boundaryPoints.size() + 1, 2);
for (uint32_t i = 0; i < boundaryPoints.size(); ++i) {
GEOSCoordSeq_setXY_r(h, seq, i, boundaryPoints[i].x0, boundaryPoints[i].y0);
}
GEOSCoordSeq_setXY_r(h, seq, (uint32_t)boundaryPoints.size(), boundaryPoints[0].x0, boundaryPoints[0].y0);
GEOSGeometry* b_ring = GEOSGeom_createLinearRing_r(h, seq);
GEOSGeometry* b_poly = GEOSGeom_createPolygon_r(h, b_ring, nullptr, 0);
GEOSGeometry* clipped = GEOSIntersection_r(h, pdp, b_poly);
GEOSGeom_destroy_r(h, pdp);
GEOSGeom_destroy_r(h, b_poly);
pdp = clipped;
}
std::vector<std::vector<CPoint2D>> results;
int n = GEOSGetNumGeometries_r(h, pdp);
for (int i = 0; i < n; ++i) {
const GEOSGeometry* g = GEOSGetGeometryN_r(h, pdp, i);
GEOSGeometry* g_simple = GEOSSimplify_r(h, g, 0.01); // <20><><EFBFBD><EFBFBD>ǰ simplify
results.push_back(GEOSPolygonToSingleLine(g_simple));
GEOSGeom_destroy_r(h, g_simple);
}
GEOSGeom_destroy_r(h, pdp);
return results;
}
void NItem::GenerateSECReserve::CalculatePDNP(const std::vector<CPoint2D>& wells, double width, double height,
double angle_deg, double gap, bool useClip, const std::vector<CPoint2D>& boundaryPoints, std::vector<std::vector<CPoint2D>>& pdnpLines)
{
GEOSGeometry* pdnp = InternalGenerateBase(wells, width, height, angle_deg, gap);
InternalClipAndExport(pdnp, boundaryPoints, useClip, pdnpLines);
}
void NItem::GenerateSECReserve::CalculatePUD(const std::vector<CPoint2D>& wells, double width, double height,
double angle_deg, double gap, double pud_mult, bool useClip, const std::vector<CPoint2D>& boundaryPoints, std::vector<std::vector<CPoint2D>>& pudLines)
{
GEOSContextHandle_t h = g_geos.handle;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>׼<EFBFBD><D7BC> PDNP <20><>״
GEOSGeometry* base_pdnp = InternalGenerateBase(wells, width, height, angle_deg, gap);
// ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
GEOSBufferParams* params = GEOSBufferParams_create_r(h);
GEOSBufferParams_setJoinStyle_r(h, params, GEOSBUF_JOIN_MITRE);
GEOSBufferParams_setMitreLimit_r(h, params, 5.0);
GEOSGeometry* expanded = GEOSBufferWithParams_r(h, base_pdnp, params, width * pud_mult);
// PUD = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - ԭʼ<D4AD><CABC><EFBFBD><EFBFBD>
GEOSGeometry* pud = GEOSDifference_r(h, expanded, base_pdnp);
// <20><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD><EFBFBD>
GEOSGeom_destroy_r(h, base_pdnp);
GEOSGeom_destroy_r(h, expanded);
GEOSBufferParams_destroy_r(h, params);
// <20>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
InternalClipAndExport(pud, boundaryPoints, useClip, pudLines);
}
/**
* <EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><EFBFBD><EFBFBD><EFBFBD>򻯲<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߵ
* Ϊ<EFBFBD>˱<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>й©<EFBFBD><EFBFBD><EFBFBD>˺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(destroy)<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> geom
*/
void NItem::GenerateSECReserve::InternalClipAndExport(GEOSGeometry* geom, const std::vector<CPoint2D>& boundaryPoints, bool useClip,
std::vector<std::vector<CPoint2D>>& outLines)
{
GEOSContextHandle_t h = g_geos.handle;
if (!geom) return;
// 1. <20>ü<EFBFBD><C3BC>߼<EFBFBD>
GEOSGeometry* finalGeom = geom;
if (useClip && boundaryPoints.size() >= 3) {
GEOSCoordSequence* seq = GEOSCoordSeq_create_r(h, (uint32_t)boundaryPoints.size() + 1, 2);
for (uint32_t i = 0; i < boundaryPoints.size(); ++i) {
GEOSCoordSeq_setXY_r(h, seq, i, boundaryPoints[i].x0, boundaryPoints[i].y0);
}
GEOSCoordSeq_setXY_r(h, seq, (uint32_t)boundaryPoints.size(), boundaryPoints[0].x0, boundaryPoints[0].y0);
GEOSGeometry* b_poly = GEOSGeom_createPolygon_r(h, GEOSGeom_createLinearRing_r(h, seq), nullptr, 0);
finalGeom = GEOSIntersection_r(h, geom, b_poly);
GEOSGeom_destroy_r(h, geom);
GEOSGeom_destroy_r(h, b_poly);
}
// 2. <20><><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD>
if (finalGeom) {
int n = GEOSGetNumGeometries_r(h, finalGeom);
for (int i = 0; i < n; ++i) {
const GEOSGeometry* g = GEOSGetGeometryN_r(h, finalGeom, i);
GEOSGeometry* g_simple = GEOSSimplify_r(h, g, 0.01);
outLines.push_back(GEOSPolygonToSingleLine(g_simple));
GEOSGeom_destroy_r(h, g_simple);
}
GEOSGeom_destroy_r(h, finalGeom);
}
}
void NItem::GenerateSECReserve::CalculateExpansion(
const std::vector<CPoint2D>& wells, double width, double height, double angle_deg, double gap, double pud_mult,
const std::vector<CPoint2D>& boundaryPoints, bool useClip,
std::vector<std::vector<CPoint2D>>& pdnpLines, std::vector<std::vector<CPoint2D>>& pudLines)
{
GEOSContextHandle_t h = g_geos.handle;
GEOSGeometry* pdnp = InternalGenerateBase(wells, width, height, angle_deg, gap);
// PUD <20><><EFBFBD><EFBFBD>
GEOSBufferParams* params = GEOSBufferParams_create_r(h);
GEOSBufferParams_setJoinStyle_r(h, params, GEOSBUF_JOIN_MITRE);
GEOSBufferParams_setMitreLimit_r(h, params, 5.0);
GEOSGeometry* expanded = GEOSBufferWithParams_r(h, pdnp, params, width * pud_mult);
GEOSGeometry* pud = GEOSDifference_r(h, expanded, pdnp);
GEOSGeom_destroy_r(h, expanded);
GEOSBufferParams_destroy_r(h, params);
// <20>ü<EFBFBD> (<28>߼<EFBFBD>ͬ PDP)...
auto clip_func = [&](GEOSGeometry* geom) {
if (!useClip || boundaryPoints.size() < 3) return geom;
GEOSCoordSequence* seq = GEOSCoordSeq_create_r(h, (uint32_t)boundaryPoints.size() + 1, 2);
for (uint32_t i = 0; i < boundaryPoints.size(); ++i) {
GEOSCoordSeq_setXY_r(h, seq, i, boundaryPoints[i].x0, boundaryPoints[i].y0);
}
GEOSCoordSeq_setXY_r(h, seq, (uint32_t)boundaryPoints.size(), boundaryPoints[0].x0, boundaryPoints[0].y0);
GEOSGeometry* b_poly = GEOSGeom_createPolygon_r(h, GEOSGeom_createLinearRing_r(h, seq), nullptr, 0);
GEOSGeometry* res = GEOSIntersection_r(h, geom, b_poly);
GEOSGeom_destroy_r(h, geom); GEOSGeom_destroy_r(h, b_poly);
return res;
};
pdnp = clip_func(pdnp);
pud = clip_func(pud);
auto to_lines = [&](GEOSGeometry* geom, std::vector<std::vector<CPoint2D>>& out) {
int n = GEOSGetNumGeometries_r(h, geom);
for (int i = 0; i < n; ++i) {
GEOSGeometry* g_simple = GEOSSimplify_r(h, GEOSGetGeometryN_r(h, geom, i), 0.01);
out.push_back(GEOSPolygonToSingleLine(g_simple));
GEOSGeom_destroy_r(h, g_simple);
}
};
to_lines(pdnp, pdnpLines);
to_lines(pud, pudLines);
GEOSGeom_destroy_r(h, pdnp); GEOSGeom_destroy_r(h, pud);
}