-
-
Notifications
You must be signed in to change notification settings - Fork 146
Object Snap
mlight lee edited this page Feb 22, 2026
·
1 revision
This page explains how OSNAP works in cad-viewer with data from realdwg-web.
In AutoCAD/ObjectARX, each entity can override getOsnapPoints(...) to return candidate snap points for a specific snap mode.
In realdwg-web, we use a similar pattern with subGetOsnapPoints(...) on each entity class.
cad-viewer consumes those returned points to perform snapping in the UI.
Reference:
- AutoCAD ObjectARX
getOsnapPoints: https://help.autodesk.com/view/OARX/2024/ENU/?guid=OARX-RefGuide-__OVERLOADED_getOsnapPoints_AcDbEntity
Base definition:
AcDbEntity.subGetOsnapPoints(osnapMode, pickPoint, lastPoint, snapPoints, gsMark?)
Parameters:
-
osnapMode: one mode each call -
pickPoint: current cursor world point -
lastPoint: previous committed point in command flow -
snapPoints: output array to append candidate points -
gsMark(optional): sub-entity id, currently important forINSERT(AcDbBlockReference) sub-entity snapping
Defined in AcDbOsnapMode:
EndPoint = 1MidPoint = 2Center = 3Node = 4Quadrant = 5Insertion = 7Perpendicular = 8Tangent = 9Nearest = 10Centroid = 11
Important:
- These values are ordinal ids, not bit flags.
- Use
acdbOsnapModesToMask(...)andacdbMaskToOsnapModes(...)for mask conversion.
Status bar (MlOsnapButton.vue) currently exposes:
- EndPoint
- MidPoint
- Center
- Node
- Quadrant
- Insertion
Not exposed in UI yet (commented out):
- Perpendicular
- Tangent
- Nearest
- Centroid
Default enabled mask in settings (AcApSettingManager):
- EndPoint + MidPoint + Center
-
AcEdFloatingInput.getPosition()callsgetOsnapPoint(). -
getOsnapPoint()callsgetOsnapPoints(). -
getOsnapPoints()runsview.pick(point, hitRadius). - For each picked item:
- resolve model-space entity by
item.id - if
item.childrenexists, call entity osnap withgsMark = child.id - otherwise call entity osnap without
gsMark
- For each active mode in current mask, call
entity.subGetOsnapPoints(...). - Choose nearest returned point to cursor.
- Apply world-distance threshold converted from screen
hitRadius(default 20 px). - If accepted, snap cursor and show marker.
-
AcDbLine: EndPoint, MidPoint, Nearest, Perpendicular (Tangentbranch exists but no point) -
AcDbArc: EndPoint, MidPoint, Nearest, Tangent (Perpendicularbranch exists but no point) -
AcDbCircle: Center, Centroid, Quadrant, Nearest, Tangent -
AcDbEllipse: EndPoint (open arc only), MidPoint (open arc only), Quadrant (closed ellipse only) -
AcDbPolyline: EndPoint -
AcDb2dPolyline: EndPoint -
AcDb3dPolyline: EndPoint -
AcDbPoint: Node -
AcDbText: Insertion -
AcDbMText: Insertion -
AcDbBlockReference(INSERT): Insertion + delegated sub-entity snapping viagsMark - Additional entities with limited support:
-
AcDbRay: EndPoint (base point) -
AcDbFace: EndPoint (vertices) -
AcDbTrace: EndPoint (vertices) -
AcDbSpline: EndPoint
subGetOsnapPoints has two paths:
-
Insertionmode:
- directly pushes block reference insertion point (
this._position)
- Other modes:
- only works when
gsMarkis provided - delegates to
subEntityGetOsnapPoints(...)
Delegation flow (subEntityGetOsnapPoints):
- Guard: if
gsMark === this.objectId, return (avoid recursion) - Resolve entity by
blockTable.getEntityById(gsMark) - Call that sub-entity’s
subGetOsnapPoints(...) - Transform returned points by this block reference
blockTransform - Push transformed points to output
- No
gsMark:
- For non-
Insertionmodes,AcDbBlockReferencereturns nothing ifgsMarkis missing.
-
gsMarkmodel is simplified:
- Current
gsMarkis sub-entity object id from spatial child hits, not full AutoCAD GS marker semantics.
- Layer-grouped rendering for INSERT:
- Rendering may split one INSERT into multiple layer-based render groups with same parent object id.
- Picking relies on hierarchical child boxes to recover sub-entity ids.
- Complex/nested/edge transforms:
- Delegation applies
blockTransformof the current INSERT. - Edge cases (for example nested block scenarios or non-default normal/extrusion cases) can still produce incorrect or missing snap points.
This matches the known roadmap note in README.md:
- Endpoint snapping for INSERT is not fully reliable yet.
- OSNAP coverage is entity-dependent; many mode/entity combinations are intentionally not implemented yet.
- INSERT non-insertion snapping depends on correct child hit ->
gsMarkpropagation. - Current marker mechanism is object-id based and not full AutoCAD GS marker behavior.
- More regression tests are needed for INSERT, especially nested blocks and transformed blocks.
- Improve robustness of child-hit to
gsMarkmapping for INSERT. - Add nested block regression tests for EndPoint/MidPoint/Center/Nearest/Tangent cases.
- Expand per-entity mode coverage incrementally.
- Align marker model closer to AutoCAD GS marker semantics when feasible.