Skip to content

【功能需求】直接解析原生天正 TCH 自定义实体(无需转 T3、无需炸开图纸),支持导出结构化 JSON([FEATURE] Parse native TArch TCH custom entities from original un-converted DWG (no T3 export / explode) for structured JSON output) #1131

Description

@xjtcnj

在中国,90% 以上的建筑图纸都由天正建筑绘制。目前全球暂无任何工具可以直接解析原生天正 DWG 文件里的 TCH 自定义实体参数,提取完整构件参数并输出结构化 JSON。现有方案只能先将图纸导出为 T3 格式再提取数据,才能生成结构化 JSON。该流程不仅增加额外人工操作,还会不可逆地丢失天正自定义构件的内置参数。如果 ACadSharp 能够支持直接解析原生天正 DWG,将会大幅提升它在国内建筑工程开发从业者中的使用率。举个例子:我本身是建筑师,并不具备编程能力,对此功能需求十分迫切。
More than 90% of architectural drawings in China are created with Tangent TArch. There is currently no tool worldwide that can directly read all complete parameters of TCH custom entities inside original native TArch DWGs and generate structured JSON.
The existing workflow requires converting drawings to T3 format before data extraction. This brings extra manual work and causes permanent, unrecoverable loss of component parameters.
If ACadSharp supports direct parsing of original Tangent DWG files, its popularity among Chinese AEC developers will be greatly improved.
I am an architect without programming background, and this feature is highly needed for my daily work.

Activity

  1. DomCR commented on Jul 5, 2026

    @DomCR
    Owner

    Hi @xjtcnj,

    I've tried to look for information about the TArch entities but I couldn't find any kind of documentation or file to use as an example.

    Could you provide some additional links for more context?
    A file with this sort of entities will help too. I'm guessing that the entities use Proxy graphics which were implemented not long ago so we may be able to read them.

    About the Json exportation, I'm working on this feature right now, is not fully integrated yet though.

  2. xjtcnj commented on Jul 5, 2026

    @xjtcnj
    Author

    File source: Original DWG saved directly by Tangent TArch (T8/T20/T30 series), no T3 conversion
    Target output: Structured JSON with full architectural component parameters
    Official software reference: https://tangent.com.cn/tzgcptxl
    Sample resource support: I am able to supply original native TArch construction drawing DWGs for testing upon request.

    目标文件:天正建筑直接保存的原生 DWG(T8/T20/T30 等版本),不经过 T3 转换
    目标输出:包含完整建筑构件参数属性的结构化 JSON
    软件官方参考链接:https://tangent.com.cn/tzgcptxl
    样例图纸支持:如维护人员需要测试文件,我可以提供原生天正施工图纸 DWG 用于开发调试

  3. DomCR commented on Jul 6, 2026

    @DomCR
    Owner

    If you can, please send some dwg files to test them, thanks!

  4. xjtcnj commented on Aug 13, 2026

    @xjtcnj
    Author

    对解析原生天正 DWG 文件的工作,开始了吗?
    Has the work for parsing native Tianzheng DWG files commenced?

  5. DomCR commented on Aug 19, 2026

    @DomCR
    Owner

    Hi @xjtcnj,

    I've looked at the issue and I think the entities are processed as proxies but is quite hard to identify the objects.

    Could you create a file with a single entity for each type that you can create from TCH like one TCH_TEXT, TCH_ARROW, TCH_MULTILEADER...?

    That way I'll be able to identify them on how Autocad process them inside the drawing.

  6. RedHaloStudio commented on Aug 19, 2026

    @RedHaloStudio

    Hi @xjtcnj,  嗨,

    I've looked at the issue and I think the entities are processed as proxies but is quite hard to identify the objects.我已经研究过这个问题了,我认为这些实体被当作代理对象来处理,但实际上很难识别出具体的对象。

    Could you create a file with a single entity for each type that you can create from TCH like one TCH_TEXT, TCH_ARROW, TCH_MULTILEADER...?您能否创建一个文件,在其中为每种可以從 TCH 中创建的类型都提供一个单独的实体?比如 TCH_TEXT、TCH_ARROW、TCH_MULTILEADER 等等。

    That way I'll be able to identify them on how Autocad process them inside the drawing.这样我就能在 AutoCAD 软件中识别它们在图纸上的显示方式了。

    TArch.zip
    There are two files inside the zip archive:
    TZ.dwg: Drawing with TZ‑specific custom entities (Tiangen objects). Requires the Tiangen plug‑in or full Tiangen software to display walls, windows and doors correctly; plain AutoCAD may render elements missing or distorted.
    TZ_t3.dwg: Standard CAD file converted to T3 format. All Tiangen custom objects have been exploded into basic CAD primitives, compatible with any standard AutoCAD version for viewing and printing.

  7. DomCR commented on Aug 19, 2026

    @DomCR
    Owner

    It seems that the objects are stored somehow in the file but they don't use the proxy graphics or any Autocad system to be rendered, as expected without the plug-in I cannot visualize them in the file, not even the bounding box of the proxy.

    To be able to retrieve the information I would need the specification of the objects and how they are stored, otherwise I'm completely blind of what I'm looking for.

    Do you have any information about the plugin that renders these objects? Or it has any specification of how it stores/renders them in Autocad?

  8. xjtcnj commented on Aug 22, 2026

    @xjtcnj
    Author
  9. DomCR commented on Aug 25, 2026

    @DomCR
    Owner

    Sadly it doesn't give me much information, if there is no specification for how it saves the entities I'm not sure it will be possible to read them.

  10. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    Image

    Image

    Image

    Image

  11. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    Image
    Image
    Image
    Image
    Image

  12. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    Image
    Image
    Image
    Image
    Image

  13. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    Image
    Image
    Image
    Image
    Image

  14. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    Image
    Image
    Image

  15. xjtcnj commented on Oct 2, 2026

    @xjtcnj
    Author

    请将这 22 个文件的后缀由 jpg 改为 rar,然后用 winRAR 解压。解压得到的文件就是天正建筑的插件。把他安装在 autocad 下,便可以打开天正建筑 dwg 文件。autocad 的版本至少应当是 2021。
    Please change the file extension of these 22 files from jpg to rar, then extract them using WinRAR. The files obtained after extraction are the plug-in for TArch. Install it under AutoCAD, and you will be able to open TArch DWG files. The AutoCAD version must be at least 2021.

  16. WallanceLee commented on Oct 8, 2026

    @WallanceLee

    Hi @DomCR,

    You asked earlier in this thread:

    To be able to retrieve the information I would need the specification of the objects and how they are stored, otherwise I'm completely blind of what I'm looking for.

    Do you have any information about the plugin that renders these objects? Or it has any specification of how it stores/renders them in Autocad?

    Yes — I reverse-engineered it, and here is a first version of that specification, sent as two PRs: #1274 and #1275.

    Where the spec comes from

    The official TArch plugin installer (T30-PlugIn V1.0.exe, 北京天正软件) ships the object implementation as
    ordinary ObjectARX modules. It is an InstallShield package, so the modules can be unpacked without running
    it. The relevant one is sys24x64/tch_kernal.arx (PE32+ x64, 10.4 MB, not packed, AutoCAD 2024); the same
    layout exists for 2019–2025.

    Crucially it keeps full MSVC RTTI, so every class resolves without symbols:
    RTTI name → TypeDescriptor → CompleteObjectLocator → vtable. For each class, vtable[31] is dwgInFields
    and vtable[32] is dwgOutFields — verified per class by requiring that dwgInFields contains a
    readByte call and dwgOutFields a writeByte call (104 of 123 classes pass).

    What the format actually is

    Tianzheng objects are written as a flat, version-tagged field sequence. No container, no compression.

    The first byte of the payload is a format version, valid values 2/3/4:

    // TDbText::dwgInFields @ 0x1C397D80
    AcDbEntity::dwgInFields(filer);                 // superclass first
    filer->readByte(&version);                      // filer vtable +0x158
    if (version > 4) return Acad::eMakeMeProxy;     // 0x12D == 301
    if (version > 2) { ... }                        // version-gated fields
    /* flat field list */
    if (version > 3) { ... }                        // more version-gated fields

    Every field goes through a small TCH helper with the signature (filer, context, tag, value), and the
    helper has two paths selected by comparing tag with 0x10:

    • tag < 0x10 → writes the native typed value (writeDouble / writeByte / writeInt16 …)
    • tag >= 0x10 → formats the value into a string and writes it with writeString

    That second path is where the TDBXDATAMAP_BLOCK_BEGIN_ / _END_ markers and readable property names such
    as PIPE_SYSTEM_NAME, DN, SHOWDNDIM come from.

    The field types, the calibration of the filer slots, and the per-class field tables for all 104 classes are
    in #1275 — I will not repeat the tables here.

    The practical finding: the block is self-describing

    This is what made it considerably easier than expected. I decoded 600 real Tianzheng proxy entities:

    600 / 600   TDBXDATAMAP_BLOCK_BEGIN_ / TDBXDATAMAP_BLOCK_END_
     184        PIPE_SYSTEM_NAME
     102        DN25                  (a value: nominal diameter 25)
      94        PIPE_OUTER_DN  /  PIPE_THICK
      86        SHOWDNDIM  /  VPIPE_DIM_*  /  ALIGNTYPE  /  DIST_DN*LAB
    

    Three things follow:

    1. Properties are stored as name/value pairs with readable ASCII names. Reading named properties needs
      neither the tag table nor the exact field order.
    2. The block is sparse — only non-default values are written, so a reader must look properties up by
      name rather than assume a fixed field set.
    3. The payload is bit-packed, so this has to sit on a bit-level reader. ACadSharp already has one.

    Two caveats I found by running it rather than reading it: some values are written natively rather than as
    text (PIPE_OUTER_DN and PIPE_THICK carry no string value at all), and name/value pairing has to be
    heuristic because a value such as DN25 looks exactly like a name.

    Two things that may also be useful

    1. Why the proxy route cannot work (confirms what you observed).

    You wrote: "they don't use the proxy graphics or any Autocad system to be rendered … I cannot visualize
    them in the file, not even the bounding box of the proxy."
    That is exactly right, and I measured it: across
    400 TCH proxy entities the saved proxy graphics stream decodes to only PUSH_MATRIX/POP_MATRIX and zero
    geometry primitives
    — consistent with your review comment on #1148.

    Where the proxy path did have a real gap is the other end of the object: the retained data was never read
    at all, and that section is the only place where the original payload survives once an object has been saved
    as a proxy. That is #1274.

    2. Identifying which Tianzheng class a proxy belongs to.

    ACAD_PROXY_ENTITY group code 91 equals 500 + the zero-based index of the class in the CLASSES section.
    I validated it against 38,437 real objects (91-500 = 75 → TCH_PIPE, and the entity sits on a PIPE-*
    layer). There is also an AcRTDxfName XDATA entry on some entities, but it is absent on many files, so 91
    is the one to rely on.

    The two PRs

    Independent changes, but together they make the DWG path work end to end:

    TchDataMap map = TchDataMap.Read(ReadAll(proxyEntity.Data), doc.Header.Version);

    Validated against a native TArch drawing

    @RedHaloStudio's TArch.zip earlier in this thread turned out to contain exactly what I was missing, so I
    ran the spec against it. TZ.dwg holds 56 native TCH objects — TCH_TEXT ×11, TCH_DIMENSION2 ×6,
    TCH_OPENING ×4, TCH_ELEVATION ×3, TCH_WALL ×2, and one each of TCH_COLUMN, TCH_AXIS_LABEL,
    TCH_RECTSTAIR, TCH_MULTILEADER, TCH_MOUNTROOF and others.

    That settles your earlier observation directly: the objects are stored natively, not as proxies, exactly as
    you said — ACadSharp reads them as UnknownEntity, never as ProxyEntity.

    Reading their payloads, the same string mechanism shows up on the native path too. Using the T3 version of
    the same drawing as an anchor, real UTF-16LE strings appear inside the native payloads:

    TCH_TEXT   bit 4154 'Wall'    bit 4266 'Window'   bit 4410 'Door'
    TCH_TEXT   bit 4154 'Square'  bit 4266 'Column'
    TCH_TEXT   bit 4154 'Section'
    

    Same bit offset across different objects of the same class, byte aligned and evenly spaced — so the payload
    is regular and decodable, and the string path of the format holds for native objects as well as proxies.

    The TDBXDATAMAP block is there in native objects too. I found the marker inside three of them
    (TCH_INDEXPOINTER, TCH_CUT, TCH_PARALLELSTAIR), which matters for the plan below: the named-property
    route is not limited to proxies, so native drawings can be read that way before the full object model exists.

    The payloads also carry type-tagged field names — T20d12, T20s8, T20u16, T20V9_dRealDist2DimLine —
    where T20 looks like a TDb encoding marker and d/s/u the field type. And the layout is stable per
    class: the same string sits at the same bit offset across every instance of a class (11/11 for TCH_TEXT,
    6/6 for TCH_DIMENSION2), so offsets can be fixed rather than discovered at runtime.

    The native sample also corrected the spec

    One thing earlier in this post needs correcting. I assumed a single format version byte with values 2/3/4.
    There are actually two, in two layers.

    The first belongs to the base class. TDbText::dwgInFields calls its superclass first, and that call target
    can be identified through the vtable — a class's dwgInFields sits at slot 31 of its own vtable:

    TDbText::dwgInFields calls 0x1C494F90  ->  slot 31 resolves to TDbEntity / TDbCurveEntity
    

    So TDbText derives from TDbEntity, and the base reader opens with its own version byte, whose valid range
    is 0..14, not 2..4 — the 2..4 byte belongs to the derived class and sits after the base class fields:

    readByte(&version);                    // filer slot +0x158
    if (version > 0x0E) return eMakeMeProxy;
    if (version > 0x08) readByte(&ctx);
    if (version > 0x09) readString(...);
    if (version > 0x0C) { ...; }

    All 44 objects agree with that layout exactly:

    bit 0 = 0x0A (10)   44/44    <= 14, valid
    bit 8 = 0x11 (17)   44/44    >= 0x10
    

    The second value matters more than it looks. The field helpers compare that ctx against 0x10 and choose
    between writing a natively typed value and formatting it into a string. 17 selects the string path, which
    is why this drawing's payloads read as text (Wall, Window, Column, Section) rather than binary. So the
    choice is per object, not a build-time constant.

    While doing that, I found a separate bug

    Worth flagging on its own, because it is why those objects are invisible to ACadSharp in the first place.

    56 notifications report the objects "has been read as an UnknownEntity", yet the document contains zero
    UnknownEntity. The cause is in the entity mode handling:

    // DwgObjectReader.readEntityMode
    if (template.EntityMode == 0)
        template.OwnerHandle = this._handlesReader.HandleReference(entity.Handle);
    else if (template.EntityMode == 1)
        this._builder.PaperSpaceEntities.Add(entity);
    else if (template.EntityMode == 2)
        this._builder.ModelSpaceEntities.Add(entity);

    DwgDocumentBuilder.PaperSpaceEntities and ModelSpaceEntities are written to but never read anywhere
    in the DWG path. The DXF path does consume its equivalent:

    // DxfDocumentBuilder
    this.ModelSpaceTemplate.OwnedObjectsHandlers.UnionWith(this.ModelSpaceEntities.Select(o => o.Handle));

    So in DWG, any entity written without an owner-relative handle (EntityMode 1 or 2) lands in a list nobody
    consumes and vanishes from the document. TArch objects are written that way. I will raise it as its own
    issue rather than fold it into #1274.

    What is still missing

    1. The derived-class version byte (2/3/4) is still not pinned down. The base class one is located — bit 0,
      value 10 in this drawing — but the derived one follows the base class fields, and those contain a
      variable-length string, so the offset has to be computed rather than read. Searching all 44 objects for a
      fixed offset holding a value in 2..4 returns nothing, which fits: the base class field length varies. What
      it needs is the exact bit encoding of AcDbDwgFiler::readString (filer slot +0xC0), which I have not
      confirmed from the disassembly yet. That is the one gap left before the field sequence can be walked
      end to end.
    2. Compound members (+0x1A8/+0x1B0, +0x198/+0x1A0) — inner layout not yet reversed. Main gap.
    3. Base classes TDbEntity / TDbCurveEntity — not extracted yet.
    4. 23 of 123 classes did not pass the verification check (mostly non-entity objects).

    What I'd do next

    1. Reverse the two compound helpers so those fields stop being opaque byte arrays.
    2. Extract the base-class chains to complete the layout.
    3. Implement TDbText (TCH_TEXT) as a fully typed reference reader, following the pattern you pointed at
      in src/ACadSharp/Entities/AecObjects/Wall.cs — a typed class plus a RawData fallback.
    4. Extend to the classes that matter most for users: TCH_WALL, TCH_OPENING, TCH_COLUMN,
      TCH_AXIS_LABEL, TCH_DIMENSION2.

    One question so I build it the way you'd want: for the object model layout, one class per TCH_*, or a
    generic carrier that exposes the parsed field list plus RawData?

    Thanks!

  17. xjtcnj commented on Oct 10, 2026

    @xjtcnj
    Author

    Hi @WallanceLee,

    Great writeup — this is very much the missing piece on our side of the workflow. Quick context: I do fire-code review of renovation projects against GB 50222-2017, which means pulling material combustion ratings (A/B1/B2/B3) straight out of Tianzheng DWG sets. Our recurring blocker: design statements and material tables live in the drawings as native TCH objects / vector curves — the proxy-graphics path recovers nothing useful, so we end up chasing the design office for a Word or PDF copy of every set.

    Three things from your post map directly onto that:

    1. The EntityMode bug is the upstream fix. Until ModelSpaceEntities/PaperSpaceEntities actually get consumed on the DWG path, none of the downstream decoding can see the objects at all. Glad you're raising it separately.
    2. Fixed per-class bit offsets for TCH_TEXT look like exactly what we need to read design-statement text straight out of the payload. If the string path holds for native objects the same way it does for proxies, that covers most of our use case before a full typed model exists.
    3. TDBXDATAMAP being self-describing matters for material tables — looking properties up by name instead of assuming a fixed field order is precisely how a reader should behave given TArch's sparse, version-gated layouts.

    On your layout question, I'd lean toward the generic carrier (parsed field list + RawData) first, with typed classes layered on as you reverse them. Reasons from our side:

    • the class list keeps growing across T20/T3/T6, and we can't wait for all 104 classes to be typed before we can read text;
    • named property access on a carrier is enough for our workflow (design-statement paragraphs, material-table entries by name);
    • a RawData fallback stays debuggable when a new TArch version shifts the offsets.

    For drawing code review scenarios covering accessibility, GB 55016 building environment, green building, civil air defense and waterproofing checks, the target is to export structured JSON data for multiple independent rule engines.

    Therefore I recommend the generic carrier design: TchObject with class name, property dictionary, raw payload and geometry.
    Lightweight typed wrappers can be added optionally for C# code convenience, but they are not the primary model and do not control JSON serialization.

    Benefits for multi-spec review:

    1. The generic model can be serialized directly to uniform JSON, consumed by different rule modules without modifying the core library for each new code or entity type.
    2. Properties dictionary naturally handles sparse TCH storage and varying TArch versions, missing attributes are omitted in JSON.
    3. Geometry and entity handles are exposed to allow cross-entity relation mapping in upper business layer.
    4. Unfinished / not-yet-reversed TCH classes can fallback to RawPayload with partial parse status, avoiding full pipeline failure.

    The library only extracts DWG/TCH data into structured objects. All specification validation logic (accessibility, daylight, civil defense etc.) belongs to the external review system and should NOT live inside ACadSharp.

    我不懂编程,也不懂英文。上文是从AI中咨询到的,不知道对你是否有帮助,也不知道能否对施工图审查提供帮助。
    建筑施工图审查有无障碍设计审查、建筑环境设计审查、绿色建筑设计审查、节能设计审查、人防工程设计审查、防水设计审查、消防设计审查、室内外装修装饰设计审查、等等。

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature added

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions