Skip to content

DWG reader: keep plot style, xref block and dimension context data; read RTEXT - #1272

Open
jarrett-meyer wants to merge 7 commits into
DomCR:masterfrom
jarrett-meyer:feature/dwg-reader-plotstyle-handles
Open

jarrett-meyer wants to merge 7 commits into
DomCR:masterfrom
jarrett-meyer:feature/dwg-reader-plotstyle-handles

Conversation

@jarrett-meyer

Copy link
Copy Markdown

The DWG reader already reads several handles and some object data and then throws them away. This PR keeps that data on the model so callers can use it, for example to plot drawings with named plot styles or to find the graphics of annotative dimensions. Each part is in its own commit.

Plot style, plot view and xref block handles

  • Entity plot style. readCommonEntityData read the plot style flags (BB) and the plot style handle and discarded both. They are now in Entity.PlotStyleFlags (0 = by layer, 1 = by block, 3 = handle present) and Entity.PlotStyleHandle. The handle points to an entry of the ACAD_PLOTSTYLENAME dictionary.
  • Layer plot style. CadLayerTemplate had the build of PlotStyleHandle commented out, so Layer.PlotStyleName was always 0 for DWG files. It is now set from the handle, as the DXF reader already does with code 390.
  • Layer xref block. The handle read into CadLayerTemplate.LayerControlHandle is the external reference block handle (the existing TODO pointed this out), and nothing used that property. It is now exposed as Layer.XrefBlockHandle, and the unused template property is removed. This gives a reliable link from an xref-dependent layer to its xref block, even when the XREF| prefix of the layer name is stale.
  • Plot settings view. The R2004+ plot view handle was read into a local variable. It is now PlotSettings.PlotViewHandle.

These are exposed as raw handles, like the existing Layer.PlotStyleName, because the plot style name entries have no model class yet. I can change them to resolved objects if you prefer.

Dimension object context data

Annotative dimensions have one ACDB_*DIMOBJECTCONTEXTDATA_CLASS object per annotation scale (aligned, rotated, radial, diametric, and so on). Each one points to the anonymous block with the dimension graphics for that scale. These objects were read as UnknownNonGraphicalObject, so the per-scale blocks could not be found.

This adds DimensionObjectContextData : AnnotScaleObjectContextData with Scale and Block. It is read for every class whose DXF name ends in DIMOBJECTCONTEXTDATA_CLASS. Only the handles are read, not the data fields. The DWG and DXF writers therefore skip it, the same way they handle other partially supported objects, and writing keeps its current behavior.

RTEXT

RTEXT (Express Tools remote text) has no class in the library and is read as UnknownEntity, so its data was lost. After the common entity data, the reader now reads the insertion point, normal, rotation, height, flags, contents (a DIESEL expression or a file name) and the text style handle into UnknownEntity.RText. A read failure only reports a warning and leaves RText null. If you prefer a dedicated RText entity instead, I can rework this part, or you can leave this commit out.

Tests

The full ACadSharp.Tests suite passes on net9.0 (2400 passed, 2 skipped). I did not add new tests. The writer does not produce named plot styles, xref-dependent layers, annotative dimensions or RTEXT, so a meaningful synthetic DWG cannot be created for these paths. They were checked against real drawings that I cannot share.

Related: the CSUtilities fix for Matrix4.GetArbitraryAxis (DomCR/CSUtilities#28) is separate. This PR does not change the submodule pointer.

A separate PR, #1271, contains DWG reader bug fixes. The two PRs are independent and merge cleanly together.

🤖 Generated with Claude Code

jarrett-meyer and others added 3 commits October 6, 2026 15:30
The DWG reader read these handles and discarded them:
- entity plot style flags and plot style handle (named plot styles),
  now Entity.PlotStyleFlags and Entity.PlotStyleHandle;
- layer plot style handle, now set to Layer.PlotStyleName as the DXF
  reader already does;
- layer external reference block handle, which was stored in an unused
  LayerControlHandle template property, now Layer.XrefBlockHandle;
- plot settings plot view handle, now PlotSettings.PlotViewHandle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Annotative dimensions have one ACDB_*DIMOBJECTCONTEXTDATA_CLASS object
per annotation scale, each pointing to the anonymous block with the
dimension graphics for that scale. These objects were read as unknown
non-graphical objects, so the per-scale blocks could not be found.

Add DimensionObjectContextData with the scale and the block, and read
it for every DIMOBJECTCONTEXTDATA class. Only the handles are read, not
the data fields, so both writers skip it like other partially supported
objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RTEXT (Express Tools remote text) has no class in the library and is read
as an UnknownEntity, losing its data. After the common entity data, read
its insertion point, normal, rotation, height, flags, contents (a DIESEL
expression or a file name) and text style handle into
UnknownEntity.RText. A read failure only reports a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

this.readCommonEntityData(template);

if (dxfClass?.DxfName == "RTEXT")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the switch in readUnlistedType following the same pattern.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: moved to case DxfFileToken.EntityRText in the readUnlistedType switch, which calls a new readRText(c). RTEXT has no class of its own in the library, so it still produces an UnknownEntity with RText filled in.

break;
}

if (template == null && c.DxfName.EndsWith("DIMOBJECTCONTEXTDATA_CLASS"))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the switch in readUnlistedType following the same pattern.

You can use "ACDB_DIMOBJECTCONTEXTDATA_CLASS".

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved into the readUnlistedType switch. A single ACDB_DIMOBJECTCONTEXTDATA_CLASS case would never match, though: DWG/DXF files store one class per dimension type, and no file declares the base name (that is why I had used EndsWith). I checked this against a drawing made in AutoCAD.

So there is now one class and one DxfFileToken constant per type, all derived from an abstract DimensionObjectContextData (AcDbDimensionObjectContextData):

  • ACDB_ALDIMOBJECTCONTEXTDATA_CLASS → AlignedDimensionObjectContextData (aligned and linear)
  • ACDB_ANGDIMOBJECTCONTEXTDATA_CLASS → AngularDimensionObjectContextData (angular and arc length)
  • ACDB_DMDIMOBJECTCONTEXTDATA_CLASS → DiametricDimensionObjectContextData
  • ACDB_ORDDIMOBJECTCONTEXTDATA_CLASS → OrdinateDimensionObjectContextData
  • ACDB_RADIMOBJECTCONTEXTDATA_CLASS → RadialDimensionObjectContextData
  • ACDB_RADIMLRGOBJECTCONTEXTDATA_CLASS → RadialDimensionLargeObjectContextData (extends the radial one)

The data fields are now read as well, from both DWG and DXF: text location and rotation, the per-scale overrides (DIMTOFL, DIMSOXD, DIMTIX and the override flags), arrow flips, and each type's points. I decoded the DWG bit layout from that AutoCAD drawing and checked it against its DXF export. One finding: DWG stores DIMATFIT and DIMTMOVE only as "overridden" bits, so their values are read from DXF only.

The drawing is in samples/annotative/, and DimensionObjectContextDataTests compares the DWG and DXF reads. Known gaps: LARGE_RADIAL_DIMENSION entities are not read yet, so the large radial context data is not covered by the tests (its layout was only checked by hand against the DXF), and the writers still skip these objects.

@DomCR DomCR added the feature New feature added label Oct 8, 2026
jarrett-meyer and others added 4 commits October 8, 2026 06:26
…e switch

Address review: dispatch both through the switch with DxfFileToken
constants instead of separate checks. DWG files store the concrete
ACDB_*DIMOBJECTCONTEXTDATA_CLASS subclass names, so each is listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DWG files store the concrete ACDB_*DIMOBJECTCONTEXTDATA_CLASS names;
there is no ACDB_DIMOBJECTCONTEXTDATA_CLASS class. Make
DimensionObjectContextData an abstract base (AcDbDimensionObjectContextData)
and add one class per type with its real DXF name and subclass marker:
aligned, angular, diametric, ordinate, radial and radial large.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Read the per-scale text location, text rotation, default text location
flag, overridden dimension variables (DIMTOFL, DIMSOXD, DIMTIX and the
override flags), arrow flips and the type-specific points of each
ACDB_*DIMOBJECTCONTEXTDATA_CLASS object, and read these objects from DXF.

The DWG bit layout was decoded from a drawing made in AutoCAD and checked
against its DXF export: text location is first, and DIMATFIT and DIMTMOVE
are stored as single override bits, so their values are only read from
DXF. The jogged radial class name is ACDB_RADIMLRGOBJECTCONTEXTDATA_CLASS
and its data extends the radial one.

Add samples/annotative with the drawing (7 annotative dimensions at 1:1
and 1:20, some with per-scale overrides) and tests comparing DWG and DXF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jarrett-meyer
jarrett-meyer force-pushed the feature/dwg-reader-plotstyle-handles branch from 17a3d30 to 17034a5 Compare October 8, 2026 12:28

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature added

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants