Skip to content

GeometryNoder: Add collection noding with per-member identity#1460

Open
pramsey wants to merge 1 commit into
libgeos:mainfrom
pramsey:main-nodewin-gn
Open

GeometryNoder: Add collection noding with per-member identity#1460
pramsey wants to merge 1 commit into
libgeos:mainfrom
pramsey:main-nodewin-gn

Conversation

@pramsey

@pramsey pramsey commented Jun 26, 2026

Copy link
Copy Markdown
Member

Extend GeometryNoder with a new nodeCollection() API that nodes a vector of geometries against each other while preserving 1:1 input/output identity: output element i is the noded form of input element i, as a MultiLineString (or MultiCurve for curved members).

This is distinct from the existing node() path, which dissolves all input into a single flat MultiLineString. Shared linework is retained in every member that touches it; point members yield empty MultiLineString slots; areal members contribute their boundary rings as noded linework, consistent with the existing single-geometry behaviour.

Snap-rounding (gridSize > 0) is supported for linear input. When any member is curved, gridSize is ignored and exact arc noding runs instead, so curve support is inherited from the existing SimpleNoder / ArcIntersectionAdder / CurveRebuilder machinery at no extra cost.

Expose the new functionality in the C API as GEOSNodeCollection(input, gridSize). A non-collection input is treated as a one-member collection.

Extend GeometryNoder with a new nodeCollection() API that nodes a vector
of geometries against each other while preserving 1:1 input/output
identity: output element i is the noded form of input element i, as a
MultiLineString (or MultiCurve for curved members).

This is distinct from the existing node() path, which dissolves all
input into a single flat MultiLineString. Shared linework is retained in
every member that touches it; point members yield empty MultiLineString
slots; areal members contribute their boundary rings as noded linework,
consistent with the existing single-geometry behaviour.

Snap-rounding (gridSize > 0) is supported for linear input. When any
member is curved, gridSize is ignored and exact arc noding runs instead,
so curve support is inherited from the existing SimpleNoder /
ArcIntersectionAdder / CurveRebuilder machinery at no extra cost.

Expose the new functionality in the C API as GEOSNodeCollection(input,
gridSize). A non-collection input is treated as a one-member collection.
@pramsey pramsey added the WIP Work in progress, do not merge. label Jun 26, 2026
Comment thread capi/geos_ts_c.cpp
geoms[i] = input->getGeometryN(i);
}

auto noded = geos::noding::GeometryNoder::nodeCollection(geoms, gridSize);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the conversion to a vector buy anything here? It seems like nodeCollection could take a collection as an argument instead of a vector. That would also clean up GeometryNoder by not having both argGeom1 and argColl members, and would remove the need for the collectionHasCurves helper.

@pramsey pramsey Jun 30, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CoverageSimplifier is the analogue I was looking at, which has

std::vector<std::unique_ptr<Geometry>>
CoverageSimplifier::simplify(
    std::vector<const Geometry*>& coverage,
    double tolerance)

as its main entry point. On the flip in the C API the entry point is

    Geometry*
    GEOSCoverageSimplifyVW(
        const Geometry* input,
        double tolerance,
        int preserveBoundary)

so.... what would you prefer?

@pramsey pramsey Jun 30, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

geom.hasCurvedComponents() in place of collectionHasCurves() I presume

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No strong preference I guess, it would just be nice if there was some way to not have all of argGeom1, argGeom2, and argColl (whose name implies a collection but is not...)

if (argGeomHasCurves) {
// Snap-rounding cannot node arcs; curved input always uses
// exact arc noding and ignores any requested gridSize.
noder = std::make_unique<SimpleNoder>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to error instead of ignoring the parameter.

Comment thread src/noding/GeometryNoder.cpp
// The arc slot stays curved: a MultiCurve of two CircularStrings.
ensure_equals("arc slot type", result[1]->getGeometryTypeId(), geos::geom::GEOS_MULTICURVE);
ensure_equals("arc split count", result[1]->getNumGeometries(), 2u);
for (std::size_t i = 0; i < result[1]->getNumGeometries(); i++) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loop from i = 0 to i = 1 seems unnecessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP Work in progress, do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants