Repository navigation
【功能需求】直接解析原生天正 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
Activity
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.
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 用于开发调试If you can, please send some dwg files to test them, thanks!
- Reacted by Albert Domenech
对解析原生天正 DWG 文件的工作,开始了吗?
Has the work for parsing native Tianzheng DWG files commenced?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.
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.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?
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.
请将这 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.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 issys24x64/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]isdwgInFields
andvtable[32]isdwgOutFields— verified per class by requiring thatdwgInFieldscontains a
readBytecall anddwgOutFieldsawriteBytecall (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 comparingtagwith0x10:tag < 0x10→ writes the native typed value (writeDouble/writeByte/writeInt16…)tag >= 0x10→ formats the value into a string and writes it withwriteString
That second path is where the
TDBXDATAMAP_BLOCK_BEGIN_/_END_markers and readable property names such
asPIPE_SYSTEM_NAME,DN,SHOWDNDIMcome 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*LABThree things follow:
- Properties are stored as name/value pairs with readable ASCII names. Reading named properties needs
neither the tag table nor the exact field order. - 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. - 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_DNandPIPE_THICKcarry no string value at all), and name/value pairing has to be
heuristic because a value such asDN25looks 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 onlyPUSH_MATRIX/POP_MATRIXand 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_ENTITYgroup code91equals500 + 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 aPIPE-*
layer). There is also anAcRTDxfNameXDATA entry on some entities, but it is absent on many files, so91
is the one to rely on.The two PRs
- feat: read the retained data of proxy entities and objects #1274 — reads the retained data of a proxy into
ProxyEntity.Data/ProxyObject.Data. Verified over
21 DWG files (1,607,215 entities) with an identical entity count and document fingerprint before and after. - feat: read Tianzheng TDBXDATAMAP property blocks #1275 — the
TchDataMapreader, plus 7 tests against real payloads.
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.zipearlier in this thread turned out to contain exactly what I was missing, so I
ran the spec against it.TZ.dwgholds 56 native TCH objects —TCH_TEXT×11,TCH_DIMENSION2×6,
TCH_OPENING×4,TCH_ELEVATION×3,TCH_WALL×2, and one each ofTCH_COLUMN,TCH_AXIS_LABEL,
TCH_RECTSTAIR,TCH_MULTILEADER,TCH_MOUNTROOFand others.That settles your earlier observation directly: the objects are stored natively, not as proxies, exactly as
you said — ACadSharp reads them asUnknownEntity, never asProxyEntity.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
TDBXDATAMAPblock 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—
whereT20looks like a TDb encoding marker andd/s/uthe 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 forTCH_TEXT,
6/6 forTCH_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::dwgInFieldscalls its superclass first, and that call target
can be identified through the vtable — a class'sdwgInFieldssits at slot 31 of its own vtable:TDbText::dwgInFields calls 0x1C494F90 -> slot 31 resolves to TDbEntity / TDbCurveEntitySo
TDbTextderives fromTDbEntity, 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 >= 0x10The second value matters more than it looks. The field helpers compare that
ctxagainst0x10and 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.PaperSpaceEntitiesandModelSpaceEntitiesare 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 (
EntityMode1 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
- 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 ofAcDbDwgFiler::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. - Compound members (
+0x1A8/+0x1B0,+0x198/+0x1A0) — inner layout not yet reversed. Main gap. - Base classes
TDbEntity/TDbCurveEntity— not extracted yet. - 23 of 123 classes did not pass the verification check (mostly non-entity objects).
What I'd do next
- Reverse the two compound helpers so those fields stop being opaque byte arrays.
- Extract the base-class chains to complete the layout.
- Implement
TDbText(TCH_TEXT) as a fully typed reference reader, following the pattern you pointed at
insrc/ACadSharp/Entities/AecObjects/Wall.cs— a typed class plus aRawDatafallback. - 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 plusRawData?Thanks!
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:
- 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.
- 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.
- 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:
TchObjectwith 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:
- 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.
- Properties dictionary naturally handles sparse TCH storage and varying TArch versions, missing attributes are omitted in JSON.
- Geometry and entity handles are exposed to allow cross-entity relation mapping in upper business layer.
- 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中咨询到的,不知道对你是否有帮助,也不知道能否对施工图审查提供帮助。
建筑施工图审查有无障碍设计审查、建筑环境设计审查、绿色建筑设计审查、节能设计审查、人防工程设计审查、防水设计审查、消防设计审查、室内外装修装饰设计审查、等等。






















在中国,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.