Skip to main content

Convert messy overlapping polylines into clean topological centerline chains

Project description

topologize

Convert messy, overlapping polylines into a clean topological skeleton.

Given a set of curves — open or closed, possibly intersecting or bundled — topologize inflates them into a region, skeletonizes that region via constrained Delaunay triangulation, and returns a list of maximal non-branching polylines tracing the medial axis.

Before and after on topologize.svg

What it does

The three-stage pipeline:

  1. Inflate — buffer all input curves by inflation_radius and union the results into one or more polygons (Clipper2)
  2. Skeletonize — constrained Delaunay triangulation of the polygon interior; midpoints of internal edges form the skeleton graph
  3. Extract chains — snap nearby endpoints, then traverse the graph to extract maximal non-branching polylines

The output chains share junction points, so the result is a proper topological graph: you can traverse it, measure it, and match it to other representations.

When to use it

Use topologize when you have geometry that approximates a graph and need an actual graph — a set of polylines with shared junction points you can traverse, measure, or match to other data.

Concrete examples:

  • Vector artwork or scanned drawings converted to machine toolpaths (laser, pen plotter, CNC, printing)
  • Road, river, or network centerline extraction from polygon or buffered line data
  • GPS or sensor traces where the same route was recorded multiple times

Installation

pip install topologize

Runtime dependency: numpy only.

To build from source (requires a Rust toolchain):

git clone https://github.com/tdamsma/topologize
cd topologize
uv run maturin develop --release

Quick start

import numpy as np
from topologize import topologize

# Any collection of (N, 2) numpy arrays — open or closed, overlapping is fine
curves = [
    np.array([[0.0, 0.0], [10.0, 0.0], [5.0, 5.0]]),
    np.array([[0.1, 0.1], [9.9, 0.1], [5.1, 4.9]]),  # near-duplicate stroke
]

result = topologize(curves, inflation_radius=0.5)
result.chains          # list of (M, 2) arrays — one per non-branching segment
result.nodes           # (K, 2) array of unique junction/endpoint positions
result.chain_node_ids  # list of (start_id, end_id) per chain

inflation_radius is the main tuning parameter. Use roughly half the typical gap between nearby strokes — small enough to keep distinct paths separate, large enough to merge strokes that belong together.

For variable-width inflation, pass a list of per-vertex radius arrays:

widths_a = np.linspace(0.3, 0.1, len(curve_a))
widths_b = np.linspace(0.1, 0.5, len(curve_b))
result = topologize([curve_a, curve_b], inflation_radius=[widths_a, widths_b])
Parameter Type Description
curves list[np.ndarray] Input polylines, each (N, 2) or (N, 3) with per-vertex widths. Closed curves should repeat the first point at the end.
inflation_radius float | list Inflation radius. A single float for uniform width, or a list of per-vertex radius arrays for variable width.
feature_size float | None Scale parameter for all derived thresholds. Defaults to inflation_radius (float) or median(all widths) (list).
simplification float | None RDP tolerance on output chains (default: feature_size / 10). Set to 0 to disable.
min_tip_length float | None Prune terminal chains shorter than this (default: feature_size * 2). Set to 0 to disable.
junction_merge_fraction float | None Merge nearby junctions within fraction × feature_size (default: 1.5). Set to 0 to disable.
compute_widths bool If True, populate result.chain_widths with estimated contour width at each chain point.

Visualization

TopologizeResult has a built-in plot() method (requires plotly):

result.plot(curves, inflation_radius=0.5)                    # basic
result.plot(curves, inflation_radius=0.5, show_triangulation=True)  # + CDT overlay

When compute_widths=True, the plot also shows bead-width envelopes around each chain.

Batch processing

For workloads with many independent curve-sets (e.g. per-layer toolpath slicing), topologize_batch processes them in parallel via Rayon with the GIL released. Each job carries its own parameters:

from topologize import topologize_batch, TopologizeJob

jobs = [
    TopologizeJob(curves_layer_1, inflation_radius=0.5),
    TopologizeJob(curves_layer_2, inflation_radius=1.0, simplification=0.0),
    # ...
]
results = topologize_batch(jobs)
# returns list[TopologizeResult], one per job

On multi-core machines this is significantly faster than a Python loop.

Async-style processing with ThreadPoolExecutor

Single topologize releases the GIL during Rust computation, so you can also use Python's ThreadPoolExecutor for async-style processing:

from concurrent.futures import ThreadPoolExecutor
from topologize import topologize

with ThreadPoolExecutor() as pool:
    futures = [pool.submit(topologize, cs, inflation_radius=0.5) for cs in curve_sets]
    results = [f.result() for f in futures]

This is useful when jobs arrive one at a time (e.g. from a queue) rather than all at once.

Examples

All examples are # %% cell-delimited Python files — run directly or open as Jupyter notebooks.

uv sync --group dev  # install plotly, svgpathtools, etc.

# Getting started — basic usage and inflation_radius tuning
uv run python/examples/getting_started.py

# SVG centerline extraction
uv run python/examples/svg_centerline.py python/examples/data/topologize.svg --buffer 0.47

# Variable-width per-vertex inflation
uv run python/examples/variable_width_demo.py

# Parallel / batch processing benchmarks
uv run python/examples/parallel_processing.py

Algorithm

See algorithm.md for a detailed description of all three pipeline stages, the boundary preprocessing steps (RDP simplification + subdivision), the post-processing applied to output chains (projection smoothing, endpoint straightening, RDP), and the rationale for the CDT midpoint approach over alternatives (Voronoi, Python prototype).

Project structure

src/
  lib.rs             pymodule entry point (_internal)
  python.rs          Python-facing bindings
  inflate.rs         Clipper2-based polygon inflation + boundary prep
  skeleton_cdt.rs    CDT midpoint-graph skeletonizer
  graph.rs           Endpoint snapping + chain extraction

python/
  topologize/
    __init__.py      Public API (TopologizeResult, topologize, topologize_batch, inflate, triangulate)
  examples/
    getting_started.py
    svg_centerline.py
    variable_width_demo.py
    compare_methods.py
    parallel_processing.py

tests/
  test_topologize.py
  test_batch.py

Cargo.toml           Rust manifest
pyproject.toml       Python build config (maturin)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

topologize-0.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl (557.9 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ i686

topologize-0.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (510.5 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARMv7l

topologize-0.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (487.9 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

topologize-0.0.4-cp313-cp313-macosx_11_0_arm64.whl (437.9 kB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

topologize-0.0.4-cp313-cp313-macosx_10_12_x86_64.whl (459.2 kB view details)

Uploaded CPython 3.13macOS 10.12+ x86-64

topologize-0.0.4-cp312-cp312-win_amd64.whl (329.6 kB view details)

Uploaded CPython 3.12Windows x86-64

topologize-0.0.4-cp312-cp312-musllinux_1_2_x86_64.whl (709.5 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ x86-64

topologize-0.0.4-cp312-cp312-musllinux_1_2_aarch64.whl (664.4 kB view details)

Uploaded CPython 3.12musllinux: musl 1.2+ ARM64

topologize-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (507.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

topologize-0.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl (558.5 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ i686

topologize-0.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (510.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARMv7l

topologize-0.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (488.4 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

topologize-0.0.4-cp312-cp312-macosx_11_0_arm64.whl (438.3 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

topologize-0.0.4-cp312-cp312-macosx_10_12_x86_64.whl (459.7 kB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

File details

Details for the file topologize-0.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 a8db018a6746a1bb527f8bd0785bd14982c3421536571379d2b1a5619acdf7c5
MD5 76431639499e6031c74760f68b8429a2
BLAKE2b-256 6317591dee97afdbec3d9414297ac442c79941e041e57e6591e8454872eaeec2

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 ca691d0687037d4e66b6e45ae2802c6447016930891cf6c5cdbb7492355db79d
MD5 1f991fb90930b99202f4da260e1e44be
BLAKE2b-256 25598f267c1f807cd986a34746572dc02b4b974af076d8be690b8c68eee99808

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f880d27e27674571c3c0ec188e482745965ec04324cef1d31eab553bda89e74f
MD5 647373464d0b6e00acbb64ba0ed5d13a
BLAKE2b-256 78c91c7f984f47dd82845f008d4965566711dfbc10f52b84188e591b4cbb5109

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0f691a979be7280aa58ffdc23dcba8bb7796bd3c2ed5d694f4e5233d0fdf63f6
MD5 3846eb50c5f356082af8bd51e9eb2a5e
BLAKE2b-256 2ae6ee2dae17081470d2a15feac8d18a19e0e3dd43dc1aedfd8b9f0604862c4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp313-cp313-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp313-cp313-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ea8c9dce3842379450c07a03f427c016511b403ce848fe89da400e8772210335
MD5 83f0b79c21af62b6030469fe3e1d51dc
BLAKE2b-256 8c7ac2b9ae8c1667ef779be9ba7120af45e21e5df92fe84ab6289082b2320215

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp313-cp313-macosx_10_12_x86_64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: topologize-0.0.4-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 329.6 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for topologize-0.0.4-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 0bcfddea26cda0b17b4db4dd54689733579e5f446ab71920e8916870a59bcb75
MD5 4de9fb94a9a75b03dba9e406983a6370
BLAKE2b-256 11551c0c6d7e7108b9d57c3ce4a8a92c860bbcbbc1d96740daf602b5a1e88f54

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-win_amd64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 06c6335aa6a1c74a3978f8d95faefa4420c84a24f3734292b31e00d6d40d94dd
MD5 b4381d94e94e9c7eeb6dfa923b886338
BLAKE2b-256 0b84dd2a07503f56c1e021c4c1e6cd165dc60652ad50b16eb3dc0caec01ba0a7

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-musllinux_1_2_x86_64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 fca7b6e4e506dace916e1d12f6a57fa2065cb4252e5337fa3c7fa47c5fa4a8b2
MD5 609bbc968496a4bd5a027b8333df5779
BLAKE2b-256 27fd595e1388f007d231702e37f8bf7089f38a3ca441e01ced8e2f06f14a4fe6

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-musllinux_1_2_aarch64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7489765bac22e477d0f1a09133c52bde1e071a25dc29f116532ee7a5995e7638
MD5 91859963642e48bf3da9267ff2d04e2b
BLAKE2b-256 f75ac4efcf198d9be6e3182899a00114793d7e44653cc17d72e52d29cca86679

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 69e88c1a32aea8fa4a96e839d0db9d08dcc6f70e6178a53c64723c5c022e90d1
MD5 3d191a99c45974b9b5c457190722d903
BLAKE2b-256 1877e562714dd7d34897fd0fb36e6548cbafd7708b293d96390c99ae1031dbce

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 090f2d35b9b38f13355d2bafe24ff062c30df06be0a3c492cce087e164adead1
MD5 2969f5a55d850441246f1e3115db417f
BLAKE2b-256 93681d1fb887f40bdb79583873f3ed1449bdfa563ea2034347b3146e9587a72f

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 687763b036637afd48bc104abc7b1764edf23285770f71868e70c901df123245
MD5 a2e8f352b760941fa0afb93f949f660c
BLAKE2b-256 41c24b28ff241872184b57bef9285a28a53102909faaf74e8e61e5450cdc4de1

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fd49925d87c7866beb63bfebfcefe30c1a1c78a3e49310f094934ff05f9e34fa
MD5 0d89cf75ba5634ef39d98e5d521078ee
BLAKE2b-256 1b9a5f83d77b865f0fabb9699440a9bd439418c971f686a0fddd12ae2ce43937

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file topologize-0.0.4-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for topologize-0.0.4-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 252ff06b15a965118f1532cf2d7bfed9db6af4664fffa0b7a6a9623e6105c2d4
MD5 6cb162f47aa53dccfc217a7582f3fbaf
BLAKE2b-256 5884e9a77f6f80768d3a3633e21d6684666fa5e79c938a568f25f3e81a0d750d

See more details on using hashes here.

Provenance

The following attestation bundles were made for topologize-0.0.4-cp312-cp312-macosx_10_12_x86_64.whl:

Publisher: ci.yml on tdamsma/topologize

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page