Expand description
Maximum inscribed circle (MIC) solvers for polygons.
The maximum inscribed circle is the largest circle that fits entirely inside a polygon. Holes are respected: the circle has to clear interior rings as well as the exterior, so the solve runs against every boundary segment.
§Quick start
use max_inscribed_circle::geo_types::{LineString, Polygon};
use max_inscribed_circle::{maximum_inscribed_circle, MicOptions};
let square = Polygon::new(
LineString::from(vec![(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 4.0), (0.0, 0.0)]),
vec![],
);
let mic = maximum_inscribed_circle(&square, &MicOptions::default())?;
assert!((mic.center.x() - 2.0).abs() < 1e-9);
assert!((mic.radius - 2.0).abs() < 1e-9);§Solve pipeline
Two stages, both native Rust. MicResult::used_engine and
MicResult::approach report which one produced the answer:
- Closed-form fast paths for single-ring inputs of four or five vertices: triangle incenter, axis-aligned rectangle, then a convex-quad Chebyshev solve. Every result is re-measured against the segment table and falls through to the grid when the ring is not the class it claimed.
- Grid search over the bounding box, a branch and bound driven by the
1-Lipschitz property of boundary distance, refining to a tolerance of
diag * 1e-7, then a compass hill climb on the clearance field.
The radius a result reports is always the measured distance from its centre
to the nearest boundary segment, so a returned circle fits the polygon. A
degenerate input, such as a zero-area ring or a non-finite coordinate, fails
fast with MicError::InvalidInput instead of returning a meaningless
circle.
§Entry points
| Function | Use |
|---|---|
maximum_inscribed_circle | one polygon |
maximum_inscribed_circle_multipolygon | best circle across components |
maximum_inscribed_circle_slice | rayon-parallel batch, input order preserved |
maximum_inscribed_circle_with_workspace | reuse a MicWorkspace across calls |
§GEOS comparison
The bench-geos feature compiles mic::solver::bench_geos, which calls
the GEOS MaximumInscribedCircle construct so benchmarks can cross-check
the native solver. It is not an engine: nothing in mic calls it, and
the default feature set does not compile it. GEOS runs the same
cell-refinement branch and bound as the grid stage, so agreement between
them means two implementations of one algorithm match, not that an
independent method confirms the radius.
§Features
| Feature | Effect |
|---|---|
bench-geos | comparison only: links the GEOS C library so benchmarks can compare solvers |
geo-traits | generic solves over any geo_traits polygon, plus geo_types::Geometry dispatch |
shewchuk | exact orient2d predicates from the robust crate in the containment and orientation tests |
simd | 4-lane batched segment distance via the stable wide crate |
hotpath | #[hotpath::measure] instrumentation on the solver entry points |
python | PyO3 extension module named max_inscribed_circle |
extension-module | build the Python module as an importable extension |
Default features are empty. The bench-geos feature links against the GEOS
C library, and its build script expects GEOS_LIB_DIR and GEOS_VERSION
when GEOS cannot be found through pkg-config.
§C ABI
ffi exposes mic_solve, mic_solve_multipolygon and
mic_options_default: flat coordinate arrays in, #[repr(C)] structs out,
0 on success and -1 on error, with panics caught at the boundary. The
Re-exports§
pub use mic::workspace::MicWorkspace;pub use mic::maximum_inscribed_circle;pub use mic::maximum_inscribed_circle_multipolygon;pub use mic::maximum_inscribed_circle_slice;pub use mic::maximum_inscribed_circle_with_workspace;pub use mic::MicApproach;pub use mic::MicError;pub use mic::MicOptions;pub use mic::MicResult;pub use mic::MicUsedEngine;pub use geo_types;
Modules§
- ffi
- C ABI for the MIC solvers (holes + multipolygon).
- geo_
interop geo-traits - georust ecosystem interop (feature
geo-traits). - mic
- Maximum Inscribed Circle (MIC) solvers for polygonal inputs.
- tuning
- MIC tuning constants carried over from IGE
ige-core::tuning.