Detecting Doors from Swing Arc Blocks
An addition to Wall & Door Detection Algorithms. Measuring the gap in a wall finds most doors; reading the swing symbol drawn beside it finds the rest and recovers two facts the gap cannot supply.
What the Symbol Carries
A door in an architectural drawing is conventionally a leaf line and a quarter-circle arc from its hinge. Both are geometry an extractor can read, and together they carry more than the wall gap does:
- Leaf width is the arc’s radius, which is the door’s actual clear width. The wall gap may be wider — a 0.9 m door in a 1.1 m structural opening is common — and the clear width is what an accessibility profile needs.
- Swing direction is the arc’s sweep and centre. Nothing in the wall geometry says which way a door opens, and there is no other source for it.
- Hinge side, which matters for the same reason.
Signatures and Their Lookalikes
The critical rule is that the arc describes a door, it does not find one. Arcs appear everywhere in architectural drawings — as fillets on corners, as furniture, as pipe bends — and an extractor that treats every 90° arc as a door produces dozens of phantom openings per floor.
Requiring a corresponding gap in a wall run at the arc’s chord removes essentially all of them. The gap remains the necessary condition; the arc supplies the detail.
Minimal Working Example
import logging
import math
from shapely.geometry import LineString, Point
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def door_from_arc(arc: dict, gaps: list[dict], *, tol: float = 0.25) -> dict | None:
"""Match a swing arc to a wall gap and return the door it describes."""
for key in ("cx", "cy", "r", "start_deg", "end_deg"):
if key not in arc:
raise KeyError(f"arc is missing {key!r}")
sweep = abs(arc["end_deg"] - arc["start_deg"]) % 360.0
if not 60.0 <= sweep <= 130.0:
return None # a door swing is a quarter turn
if not 0.6 <= arc["r"] <= 1.6:
return None # outside any real door leaf width
hinge = Point(arc["cx"], arc["cy"])
end = Point(arc["cx"] + arc["r"] * math.cos(math.radians(arc["end_deg"])),
arc["cy"] + arc["r"] * math.sin(math.radians(arc["end_deg"])))
chord = LineString([hinge, end])
for gap in gaps:
centre = Point(gap["x"], gap["y"])
if chord.distance(centre) > tol:
continue
return {"x": gap["x"], "y": gap["y"],
"clear_width_m": round(arc["r"], 3),
"opening_width_m": gap["width"],
"swing_deg": round(arc["start_deg"], 1),
"hinge": (arc["cx"], arc["cy"]),
"source": "swing_arc"}
logger.info("arc at (%.2f, %.2f) r=%.2f has no matching wall gap; ignored",
arc["cx"], arc["cy"], arc["r"])
return None
The two filters before the geometric match — a sweep between 60° and 130°, and a radius between 0.6 m and 1.6 m — remove the overwhelming majority of non-door arcs before any spatial work runs, which matters because the spatial match is the expensive part.
Common Errors & Fixes
Phantom doors on every corner. Fillet arcs are being accepted. Both the radius filter and the gap requirement should exclude them; a fillet has a radius of a few centimetres and no wall gap.
Double doors counted twice. Two arcs share a hinge line and both match the same gap. Merge openings closer than about 0.4 m, summing their clear widths, exactly as node placement does downstream — doing it here as well means the merged width is available to detection.
Clear width is larger than the opening. The arc belongs to a different door. Tighten the chord tolerance, and prefer the gap when the two disagree by more than a few centimetres.
Swing direction is recorded and never used. Worth checking, because the field is only useful if something consumes it. Turn-by-turn generation should say “pull the door” where the swing faces the traveller, and an accessibility profile with a door-operating-force rule needs the hinge side to reason about approach clearance. A field that is populated and ignored is a maintenance cost with no benefit; either wire it up or stop recording it.
No arcs anywhere, but doors exist. The drawing uses door blocks rather than exploded arcs. Look
for INSERT entities whose block name matches a door pattern and read the width from the block
definition — the same information, in a different form, as the
ezdxf entity reference
describes.
Integration Point
Swing detection runs inside wall and door detection, after gaps have been measured and before openings are emitted. Its output enriches the opening record rather than replacing it: the gap supplies the position and the structural opening width, the arc supplies clear width and swing.
Those extra fields matter downstream. Clear width is what
accessible routing profiles
tests against a minimum; swing direction is what a turn-by-turn generator uses to say “pull the
door towards you”, and what
IMDF publication
carries on an opening feature.
Frequently Asked Questions
Is the swing arc reliable enough to trust for clear width?
For the leaf itself, yes; for the clear opening a wheelchair actually passes through, nearly. The arc radius is the door leaf’s width as drawn, which is what the manufacturer supplies and what the architect specified. The genuine clear width is slightly less, because an open leaf at 90 degrees still intrudes by its thickness and the frame takes a few millimetres — typically 30 to 50 mm in total. Where the distinction matters, subtract a fixed allowance rather than trying to model it; where it does not, the arc radius is a much better estimate than the structural gap.
What about sliding and revolving doors?
Both need their own signatures and both matter for accessibility. A sliding door is drawn as a leaf parallel to the wall with no arc, so the gap rule finds it and the swing rule does not — which is correct, since it has no swing. A revolving door is drawn as a circle with radial leaves and is usually accompanied by a separate pass door; detecting the circle and treating it as impassable for step-free and service profiles, while routing those profiles through the pass door, is the behaviour every accessibility profile expects.
Should a door without a swing arc be treated differently?
Only in what is recorded, not in whether it is a door. The gap is the evidence that an opening exists; the arc is extra detail. A door found by gap alone should be emitted with its structural opening width and a null swing direction, so consumers can tell the difference between “opens outward” and “we do not know”. Filling in a default swing would be worse than leaving it null, because a turn-by-turn instruction that tells someone to push a door that pulls is actively unhelpful.
Related
- Wall & Door Detection Algorithms — the gap-based detection this enriches.
- Automating Wall and Door Detection in CAD — the offset-pair and gap-width measurements this builds on.
- Accessible Routing Profiles — the consumer of clear width and swing direction.
This page is a companion to Wall & Door Detection Algorithms, part of the Automated Floor Plan Parsing & Vectorization section.