Objektové snapping (OSNAP)
Tato stránka vysvětluje, jak OSNAP funguje v cad-viewer s daty z realdwg-web.
Pozadí
V AutoCADu/ObjectARX může každá entita přepsat getOsnapPoints(...) a vrátit kandidátské snap body pro konkrétní režim snappingu.
V realdwg-web používáme podobný vzor s subGetOsnapPoints(...) na každé třídě entity.cad-viewer tyto vrácené body spotřebovává a provádí snapping v uživatelském rozhraní.
Reference:
- AutoCAD ObjectARX
getOsnapPoints: https://help.autodesk.com/view/OARX/2024/ENU/?guid=OARX-RefGuide-__OVERLOADED_getOsnapPoints_AcDbEntity
Základní API v realdwg-web
Základní definice:
AcDbEntity.subGetOsnapPoints(osnapMode, pickPoint, lastPoint, snapPoints, gsMark?)
Parametry:
osnapMode: jeden režim při každém volánípickPoint: aktuální světový bod kurzorulastPoint: předchozí potvrzený bod v toku příkazusnapPoints: výstupní pole, do kterého se připojují kandidátské bodygsMark(volitelný): ID podřízené entity, aktuálně důležité pro snapping podřízených entitINSERT(AcDbBlockReference)
Podporované režimy OSNAP
Definováno v AcDbOsnapMode:
EndPoint = 1MidPoint = 2Center = 3Node = 4Quadrant = 5Insertion = 7Perpendicular = 8Tangent = 9Nearest = 10Centroid = 11
Důležité:
- Tyto hodnoty jsou ordinální ID, nikoli bitové příznaky.
- Pro převod masky používejte
acdbOsnapModesToMask(...)aacdbMaskToOsnapModes(...).
Aktuální nabídka v uživatelském rozhraní cad-viewer
Stavový řádek (MlOsnapButton.vue) aktuálně nabízí:
- EndPoint
- MidPoint
- Center
- Node
- Quadrant
- Insertion
V uživatelském rozhraní zatím nejsou nabízeny (zakomentováno):
- Perpendicular
- Tangent
- Nearest
- Centroid
Výchozí povolená maska v nastavení (AcApSettingManager):
- EndPoint + MidPoint + Center
Běhový tok v cad-simple-viewer
AcEdFloatingInput.getPosition()volágetOsnapPoint().getOsnapPoint()volágetOsnapPoints().getOsnapPoints()spouštíview.pick(point, hitRadius).- Pro každou vybranou položku:
- rozpoznejte entitu v modelovém prostoru podle
item.id - pokud existuje
item.children, zavolejte osnap entity sgsMark = child.id - jinak zavolejte osnap entity bez
gsMark
- Pro každý aktivní režim v aktuální masce zavolejte
entity.subGetOsnapPoints(...). - Vyberte nejbližší vrácený bod ke kurzoru.
- Aplikujte prahovou hodnotu světové vzdálenosti převedenou ze obrazovkového
hitRadius(výchozí 20 px). - Pokud je bod přijat, přichyťte kurzor a zobrazte značku.
Přehled implementace entit (z kódu realdwg-web)
AcDbLine: EndPoint, MidPoint, Nearest, Perpendicular (větevTangentexistuje, ale bez bodu)AcDbArc: EndPoint, MidPoint, Nearest, Tangent (větevPerpendicularexistuje, ale bez bodu)AcDbCircle: Center, Centroid, Quadrant, Nearest, TangentAcDbEllipse: EndPoint (pouze otevřený oblouk), MidPoint (pouze otevřený oblouk), Quadrant (pouze uzavřená elipsa)AcDbPolyline: EndPointAcDb2dPolyline: EndPointAcDb3dPolyline: EndPointAcDbPoint: NodeAcDbText: InsertionAcDbMText: InsertionAcDbBlockReference(INSERT): Insertion + delegovaný snapping podřízených entit přesgsMark- Další entity s omezenou podporou:
AcDbRay: EndPoint (základní bod)AcDbFace: EndPoint (vrcholy)AcDbTrace: EndPoint (vrcholy)AcDbSpline: EndPoint
Logika OSNAP pro INSERT (AcDbBlockReference)
subGetOsnapPoints má dvě cesty:
- Režim
Insertion:
- přímo přidá bod vložení blokové reference (
this._position)
- Ostatní režimy:
- funguje pouze tehdy, je-li zadán
gsMark - deleguje na
subEntityGetOsnapPoints(...)
Tok delegace (subEntityGetOsnapPoints):
- Ochrana: pokud
gsMark === this.objectId, vraťte se (vyhněte se rekurzi) - Rozpoznejte entitu pomocí
blockTable.getEntityById(gsMark) - Zavolejte
subGetOsnapPoints(...)této podřízené entity - Transformujte vrácené body pomocí
blockTransformtéto blokové reference - Připojte transformované body do výstupu
Proč snapping pro INSERT může selhat (současné chování)
- Žádný
gsMark:
- Pro režimy jiné než
InsertionnevracíAcDbBlockReferencenic, pokudgsMarkchybí.
- Model
gsMarkje zjednodušený:
- Aktuální
gsMarkje ID objektu podřízené entity z prostorových zásahů potomků, nikoli plná sémantika GS markerů AutoCADu.
- Vykreslování INSERT seskupené podle hladin:
- Vykreslování může rozdělit jeden INSERT do více skupin vykreslování podle hladin se stejným ID rodičovského objektu.
- Výběr se spoléhá na hierarchické boxy potomků při zpětném zjišťování ID podřízených entit.
- Složité/vnořené/okrajové transformace:
- Delegace aplikuje
blockTransformaktuálního INSERT. - Okrajové případy (například scénáře s vnořenými bloky nebo nestandardní případy normály/extruze) mohou stále produkovat nesprávné nebo chybějící snap body.
To odpovídá známé poznámce v plánu vývoje v README.md:
- Snapping koncových bodů pro INSERT zatím není plně spolehlivý.
Známá omezení / TODO
- Pokrytí OSNAP závisí na entitě; mnoho kombinací režimu a entity záměrně zatím není implementováno.
- Snapping INSERT mimo bod vložení závisí na správném šíření zásahu potomka ->
gsMark. - Aktuální mechanismus značek je založen na ID objektu a nejde o plné chování GS markerů AutoCADu.
- Je potřeba více regresních testů pro INSERT, zejména pro vnořené bloky a transformované bloky.
Doporučený směr přispívání
- Zlepšit robustnost mapování zásahu potomka na
gsMarkpro INSERT. - Přidat regresní testy vnořených bloků pro případy EndPoint/MidPoint/Center/Nearest/Tangent.
- Postupně rozšiřovat pokrytí režimů pro jednotlivé entity.
- Pokud je to proveditelné, přiblížit model značek sémantice GS markerů AutoCADu.