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