Free mask → regions → clearance
5.02 принимает уже готовый FreeMask 5.01. Его задача — понять, из скольких связных пустых областей он состоит и какой локальный геометрический запас есть внутри каждой.
Connected EmptyRegion[], Euclidean clearance field, maximum inscribed radius и local breathing-room query.
Occupied/free mask, figure-ground relations, corridor semantics, whitespace score.
CONNECTED FREE-REGION / CLEARANCE GEOMETRY ONLY.
EmptyRegion[]
Каждая связная компонента free mask становится отдельным EmptyRegion.
EmptyRegion
{
regionId,
freeMaskRef,
domainRef,
componentIndex,
areaPx2,
areaFractionOfFreeSpace,
areaFractionOfDomain,
touchesDomainBoundary,
isInteriorPocket,
boundaryRefs[],
distanceFieldRef,
maxClearance,
exactness,
confidence,
provenance
}Area identities
4/8 connectivity нельзя угадывать
В vector topology вопрос естественный. В raster fallback диагональное касание требует явной digital-topology policy.
Dual pair A
freeConnectivity = 4 occupiedConnectivity = 8 diagonal free cells → disconnected
Dual pair B
freeConnectivity = 8 occupiedConnectivity = 4 diagonal free cells → connected
FreeSpaceDistanceField
Clearance определяется внутри free region как расстояние до ближайшей границы именно этой свободной области.
Largest inscribed empty disk
Максимум clearance — геометрическая ёмкость одного EmptyRegion.
Maximum
Meaning
center: maxClearancePoint radius: maxClearancePx disk: largest empty disk inscribed in R NOT: corridor width whitespace score balance
BreathingRoomQuery
`Breathing room` в 5.02 — удобное имя для локального clearance query, а не эстетический verdict.
BreathingRoomQuery {
queryId,
point,
freeMaskRef,
distanceFieldRef,
normalizationContextRef?
}
BreathingRoomQueryResult {
queryPoint,
regionId,
localRadiusPx,
localRadiusShortN?,
status,
confidence,
provenance
}
Край canvas — тоже граница
Если free region касается края domain, clearance ограничивается и этим краем.
Per-region area ≠ total free area
5.01 и 5.02 делят ownership по масштабу объекта измерения.
| Metric | Owner | Meaning |
|---|---|---|
space.mask.freeAreaPx2 | 5.01 | весь FreeMask |
space.mask.freeFraction | 5.01 | весь FreeMask / domain |
space.region.count | 5.02 | число connected free components |
space.region.areaPx2 | 5.02 | площадь конкретного EmptyRegion |
space.region.areaFractionOfFreeSpace | 5.02 | доля конкретного region внутри total free space |
Sampling invariance и error bounds
Mean clearance намеренно не канонизирован: он легко зависит от raster resolution и measure weighting.
Preferred
VECTOR_MEDIAL ANALYTIC exact/controlled distance to region boundary
Fallback
RASTER_EDT RASTER_CENTER_SAMPLED deterministic declared cellSize declared errorBound
Clearance ≠ corridor width
Формула `2×radius` похожа на ширину только в специальных местах medial geometry.
5.02
Distance field, local radius, max inscribed radius.
5.03
Corridor/channel/enclosure relations и их region-object semantics.
5.04
Target-aware «слишком узко / достаточно / намеренно плотно».
Edge cases
Пустая область и отсутствие области — разные состояния.
| Case | EmptyRegion result |
|---|---|
| FreeMask empty / domain fully occupied | regionCount=0; no zero-area pseudo-region |
| Domain completely free | обычно 1 boundary-touching region |
| two regions separated by occupied barrier | regionCount=2 |
| diagonal-only raster contact | depends explicitly on 4/8 connectivity policy |
| query on occupied point | breathing room=N/A |
| query outside domain | N/A |
| shortSidePx missing | Px clearance valid; ShortN=N/A |
Correction routing
5.02 не расширяет пустоту сам.
Mask wrong
→ 5.01.
Geometry wrong
→ Topic 3.
Relation meaning
→ 5.03.
Too tight for target
→ 5.04 / future solver.
Visual Lab
Connectedness и clearance показаны как geometry descriptors.
Reference region / clearance tests
Reference runner использует binary cell-union geometry: connected components exact for declared digital topology; clearance — deterministic center-sampled Euclidean approximation with explicit cell scale.
DATA FOR LAYOUT ENGINE
Machine-readable contract 5.02.
{
"module": "Compo 5.02",
"name": "connected_empty_regions_clearance_and_breathing_room",
"version": "1.1-corrective",
"scope": "CONNECTED_FREE_SPACE_REGIONS_DISTANCE_TO_FREE_BOUNDARY_AND_LOCAL_BREATHING_ROOM",
"consumes": [
"Compo5.01.SpaceMaskPairResult",
"Compo5.01.FreeSpaceMaskResult",
"Compo5.00.CompositionSpaceDomain",
"SpaceRegionTopologyPolicy",
"DistanceMetricPolicy",
"CanvasNormalizationContext.shortSidePx? from external owner",
"vector/raster mask representation adapter"
],
"provides": [
"EmptyRegion",
"EmptyRegionSet",
"FreeSpaceDistanceField",
"ClearanceMaximumDescriptor",
"BreathingRoomQuery",
"BreathingRoomQueryResult",
"MetricResult[space.region.count]",
"MetricResult[space.region.areaPx2]",
"MetricResult[space.region.areaFractionOfFreeSpace]",
"MetricResult[space.region.areaFractionOfDomain]",
"MetricResult[space.region.maxClearancePx]",
"MetricResult[space.region.maxClearanceShortN]",
"MetricResult[space.region.confidence]",
"SpaceRegionCorrectionRequest[]"
],
"owns_metrics": [
"space.region.count",
"space.region.areaPx2",
"space.region.areaFractionOfFreeSpace",
"space.region.areaFractionOfDomain",
"space.region.maxClearancePx",
"space.region.maxClearanceShortN",
"space.region.confidence"
],
"descriptors_only": [
"space.region.regionId",
"space.region.componentIndex",
"space.region.touchesDomainBoundary",
"space.region.isInteriorPocket",
"space.region.boundaryRefs[]",
"space.region.maxClearancePoint",
"space.region.distanceFieldRef",
"space.region.exactness",
"space.region.approximationErrorBoundPx",
"space.region.status",
"space.breathingRoom.localRadiusPx",
"space.breathingRoom.localRadiusShortN",
"space.breathingRoom.queryPoint",
"space.breathingRoom.status",
"space.region.setStatus"
],
"empty_region_schema": {
"regionId": "stable deterministic id inside mask/version",
"freeMaskRef": "Compo5.01 ref",
"domainRef": "same CompositionSpaceDomain",
"componentIndex": "integer >=0",
"areaPx2": "region-specific area; sum across regions equals 5.01 freeAreaPx2 within tolerance",
"areaFractionOfFreeSpace": "regionArea / totalFreeArea",
"areaFractionOfDomain": "regionArea / domainArea",
"touchesDomainBoundary": "boolean geometric descriptor",
"isInteriorPocket": "!touchesDomainBoundary descriptor only; not a quality judgment",
"boundaryRefs": "resolved free-region boundary refs[]",
"distanceFieldRef": "FreeSpaceDistanceField ref",
"maxClearance": "ClearanceMaximumDescriptor",
"exactness": "EXACT|BOUNDED_APPROXIMATION",
"confidence": "0..1",
"provenance": "object"
},
"distance_field_schema": {
"fieldRef": "string",
"regionId": "EmptyRegion ref",
"metric": "EUCLIDEAN_TO_FREE_REGION_BOUNDARY",
"definition": "for p inside region, distance to nearest point on boundary of the same free region; boundary includes occupied-support boundary and CompositionSpaceDomain boundary",
"representation": "ANALYTIC|VECTOR_MEDIAL|RASTER_EDT|RASTER_CENTER_SAMPLED|CUSTOM",
"queryDomain": "inside the free region only",
"outsideOrOccupied": "N_A, not zero",
"errorBoundPx": "required for approximation",
"confidence": "0..1",
"provenance": "object"
},
"clearance_semantics": {
"localClearance": "distance from a free-space point to nearest boundary of its free region",
"maxClearancePx": "maximum localClearance over one EmptyRegion; radius of a largest inscribed empty disk under the declared geometry/approximation",
"maxClearanceShortN": "maxClearancePx / shortSidePx when normalization context is valid",
"breathingRoom": "query-level alias/consumer-facing descriptor for localClearance at an explicit point; not an aesthetic score",
"diameter_note": "clearance is a radius. A local empty corridor width may be approximately 2*radius only in specific medial/channel geometry; corridor width semantics are deferred to 5.03"
},
"region_topology_policy": {
"vector": "connected components of FreeMask under continuous planar topology",
"raster": "connectivity must be explicit",
"raster_allowed_pairs": [
{
"freeConnectivity": 4,
"occupiedConnectivity": 8
},
{
"freeConnectivity": 8,
"occupiedConnectivity": 4
}
],
"dual_connectivity_reason": "avoid ambiguous diagonal foreground/background connectivity in digital topology",
"default_reference_fixture": {
"freeConnectivity": 4,
"occupiedConnectivity": 8,
"provenance": "STYLE_PRESET"
}
},
"area_policy": {
"region_area": "measure each connected free component",
"sum_identity": "sum(region.areaPx2) = Compo5.01.freeAreaPx2 within mask exactness/error tolerance",
"areaFractionOfFreeSpace": "regionArea/freeArea; N/A when freeArea=0 because there are no EmptyRegion records",
"areaFractionOfDomain": "regionArea/domainArea",
"ordering": "canonical serialization by area descending, then stable geometry/signature id; ordering is not quality"
},
"clearance_policy": {
"preferred_metric": "Euclidean distance",
"domain_boundary": "counts as free-region boundary",
"occupied_boundary": "counts as free-region boundary",
"other_free_regions": "not directly relevant because distinct components are separated by non-free boundary",
"exact_vector": "analytic/medial-axis adapter when robust",
"raster_fallback": "deterministic Euclidean distance transform / center-sampled bounded approximation",
"sampling_error": "must be declared; reference center-sampling error <= sqrt(2)/2 cellSize for locating continuous maximum on a cell-union region",
"mean_clearance": "not canonical in 5.02 because sampling/measure weighting policy would need a separate explicit integration contract"
},
"breathing_room_query_schema": {
"queryId": "string",
"point": "domain-coordinate point",
"freeMaskRef": "5.01 ref",
"distanceFieldRef": "5.02 ref",
"normalizationContextRef": "optional",
"returns": "localRadiusPx/localRadiusShortN/status/confidence/provenance"
},
"metric_policy": {
"regionCount": "topological descriptor only",
"regionArea": "region-specific geometry descriptor; total free area remains owned by 5.01",
"maxClearance": "geometric capacity descriptor only",
"breathingRoom": "local query descriptor only",
"direct_scoring": "FORBIDDEN in 5.02",
"more_regions_is_better": "FORBIDDEN",
"larger_clearance_is_better": "FORBIDDEN",
"larger_region_is_better": "FORBIDDEN",
"target_interpretation": "deferred to Compo5.04"
},
"hard_constraints": [
"one metric = one owner",
"5.02 consumes the canonical FreeMask from 5.01 and must not rebuild occupied/free masks under new names",
"sum of EmptyRegion areas must reconcile with 5.01 freeArea within declared tolerance",
"raster connectivity policy must be explicit; 4/8 diagonal ambiguity must not be guessed",
"FreeSpaceDistanceField is defined only inside free space; occupied/outside query is N/A, not zero breathing room",
"CompositionSpaceDomain boundary participates in free-region boundary distance",
"maxClearance is a radius, not corridor width",
"mean clearance is not published without an explicit measure/integration policy",
"isInteriorPocket is a topology descriptor only and not enclosure/figure-ground interpretation",
"region-object ownership/enclosure/channel/corridor relations remain Compo5.03",
"5.01 total freeArea/freeFraction ownership is retained; 5.02 owns only per-region area descriptors and region count",
"4.01 hullOccupancy remains unrelated object-internal metric",
"visual mass remains Topic4",
"canvas short-side normalization is consumed from external owner, not owned",
"more clearance or more free regions is not universally better",
"zero free area yields zero EmptyRegions, not one zero-area region",
"explicit full-free domain may yield one boundary-touching EmptyRegion",
"N/A != 0",
"no local whitespace quality score in 5.02",
"global balance/hierarchy/eye-flow remain future owners",
"no beautyScore",
"EmptyRegionSet must carry status so an explicit zero-region result is distinguishable from missing region evidence",
"5.04 must consume EmptyRegionSet.status; undefined/missing regions must never be interpreted as regionCount=0"
],
"initial_heuristics": {
"region_area_reconciliation_tolerance_px2": {
"value": 1e-06,
"provenance": "IMPLEMENTATION_HEURISTIC"
},
"distance_epsilon_px": {
"value": 1e-09,
"provenance": "IMPLEMENTATION_HEURISTIC"
},
"reference_raster_connectivity": {
"value": {
"freeConnectivity": 4,
"occupiedConnectivity": 8
},
"provenance": "STYLE_PRESET"
}
},
"correction_policy": {
"foreign_mask_mutation": "FORBIDDEN",
"mask_inconsistency": "route to Compo5.01",
"domain_issue": "route to canvas/domain owner",
"distance_backend_failure": "request exact/fallback distance-field adapter with explicit error bound",
"connectivity_policy_missing": "request explicit SpaceRegionTopologyPolicy",
"region_object_relation_issue": "route to Compo5.03",
"whitespace_target_issue": "route to Compo5.04",
"object_geometry_issue": "route to Topic3 owner"
},
"deferred_inputs": [
"Compo5.03 figure-ground / enclosure / corridor / channel relations",
"Compo5.04 target-aware scoring/corrections/regression",
"Topic6 canonical canvas/format normalization",
"future global balance/hierarchy/eye-flow"
],
"recompute_when": [
"5.01 FreeMask changes",
"CompositionSpaceDomain changes",
"raster/vector connectivity/topology policy changes",
"distance metric/backend changes",
"normalization shortSidePx changes",
"mask approximation/error policy changes"
],
"finality": "CONNECTED_FREE_REGION_AND_CLEARANCE_GEOMETRY_ONLY",
"empty_region_set_schema": {
"freeMaskRef": "Compo5.01 ref",
"status": "OK|PARTIAL|N_A|INVALID",
"regions": "EmptyRegion[]",
"regionCount": "integer >=0 only when status=OK",
"freeAreaPx2": "copied/reference value from 5.01 for reconciliation only; ownership stays 5.01",
"topologyPolicyRef": "explicit vector/raster connectivity policy",
"confidence": "0..1",
"provenance": "object",
"zero_vs_missing": "status=OK + regions=[] means valid zero free regions; status=N_A/PARTIAL is missing/incomplete evidence"
}
}