02CadGis

Universal CAD/GIS Importer — Academic Reference Manual
v2.8.1 · Yusuf Eminoğlu · Dokuz Eylül University, Dept. of City & Regional Planning · August 2026 · GitHub

Architecture & Design

Overview & Design Philosophy

02CadGis converts CAD and GIS exchange files into clean, styled GeoPackage layers. It is built for planning, cadastral, and municipal workflows where AutoCAD DWG/DXF, Netcad NCZ/NCA, KML/KMZ, GML, GeoJSON, CSV/TSV, SpatiaLite, GPX, DGN, FileGDB, and Personal GDB (.mdb) files must become QGIS data quickly and without data loss.

The plugin rests on five principles:

  1. No silent data loss. Every readable feature is written. Problematic geometries are repaired, not dropped. Empty entities are filtered with a logged warning, never a fatal error.
  2. Selective conversion. The layer tree shows what is in the file before conversion. Unchecked layers cost zero decode time.
  3. Format-native parsers where GDAL falls short. The plugin carries its own NCZ parser, DGN v8 reader, CSV sniffer, and MS Access reader — each activating when the corresponding GDAL driver is absent or incomplete.
  4. Turkish planning data is a first-class citizen. The CRS detector knows every EPSG code in the Turkish survey projection families. The PlanGML engine applies the official Ministry e-Plan symbology. The mojibake repairer recovers Turkish characters from mis-encoded CAD layers.
  5. Progressive disclosure. The dock shows only the controls relevant to the selected input type. Drag-and-drop auto-detects format and switches tabs.

Three-Engine Architecture

EngineFormatsCore ModuleParser
CADDXF, DWG, DGNcore/cad_engine.pyGDAL/OGR with CadCleanupEngine post-processing. DWG: 3-tier fallback (GDAL → ODA → LibreDWG). DGN: GDAL → pure-Python fallback.
GISKML, KMZ, GML, GeoJSON, CSV/TSV, SpatiaLite, GPX, FileGDB, Personal GDBcore/gis_engine.pyGDAL/OGR with format-specific pre-processing. CSV sniffer for delimited text. KMZ multi-document extraction. GDB live zero-copy mode. MS Access pure-Python reader.
NCZ v2NCZ, NCAcore/ncz_engine/v2/Independent block-oriented binary decoder: lazy catalog → selective decode → index cache. Five cooperating modules: binary reader, parser, geometry decoder, attribute decoder, block catalogue.

Dock Panel & Drag-and-Drop

The dock has three stacked panels: CAD & GIS Converter (source selection, layer tree, output options), Netcad NCZ/NCA Importer (multi-file, metadata, CRS, PlanGML), and CAD & GIS Exporter (DXF/KML/KMZ output). Dropping any supported file onto the dock auto-detects the format and switches to the correct panel. Session preferences — target path, CRS, cleanup options, last-used folders — persist via QSettings.

Theoretical Background

CAD-to-GIS Conversion Theory

The conversion of data between Computer-Aided Design (CAD) and Geographic Information Systems (GIS) environments constitutes a well-recognised interoperability challenge. CAD systems model physical space through geometric primitives — points, lines, arcs, polylines, circles, and blocks — organised into named layers that often encode functional categories implicitly. GIS, by contrast, represents geographic phenomena as features with explicitly typed attribute schemas, governed by a coordinate reference system and stored in geo-relational or object-relational databases [Zhu et al. 2018; Liu et al. 2017].

The fundamental discrepancy arises from divergent data modelling paradigms. CAD employs a drawing-centric model in which geometry is the primary artefact and attributes (colours, line weights, layer names, text annotations) are decoration. GIS employs a feature-centric model in which each spatial object carries a structured set of properties and belongs to a formally typed geometry class. Bridging these paradigms requires solving four sub-problems:

  1. Geometry extraction — reading coordinate sequences from binary or text formats and constructing valid OGC Simple Features geometries.
  2. Layer/feature mapping — assigning CAD entities to GIS feature classes based on layer names, block references, or attribute tables.
  3. Coordinate transformation — resolving the source CRS (often implicit or locally defined in CAD) and transforming to a target CRS suitable for GIS analysis.
  4. Semantic enrichment — populating GIS attribute tables from CAD annotations, block attributes, embedded tables, or external catalogues.

The C2G framework proposed by Al-Sabban et al. (2022) formalises this as a five-stage pipeline: Pre-processing, Geometry Conversion, Attribute Mapping, Quality Assurance, and Post-processing. 02CadGis implements each stage, with the quality-assurance stage embodied in the collinear simplification engine and the feature-count verification gates that prevent silent data loss [Al-Sabban et al. 2022].

Definition 1 — CAD-to-GIS Conversion

Let \(C = \{(\gamma_i, \ell_i, \alpha_i)\}\) be a CAD drawing, where \(\gamma_i\) is a geometric primitive, \(\ell_i \in L\) its layer assignment from the set of drawing layers \(L\), and \(\alpha_i\) its attribute vector (colour, line weight, text). A CAD-to-GIS converter is a function \(f: C \to G\) where \(G = \{(F_j, A_j)\}\) is a set of GIS feature classes \(F_j\) (each carrying a homogeneous geometry type and a CRS) with attribute schemas \(A_j\), such that every \(\gamma_i\) is assigned to exactly one \(F_j\) and its geometric fidelity is preserved within floating-point tolerance \(\varepsilon\).

Coordinate Reference Systems in CAD/GIS Conversion

Coordinate Reference Systems (CRS) present the most consequential failure mode in CAD-to-GIS conversion. A CAD drawing stores coordinates as absolute numeric values in a local Cartesian space, often with no explicit CRS metadata. When the drawing represents a real-world site, those coordinates are in some projected coordinate system — but identifying which one requires external knowledge.

In Turkish planning practice, the situation is especially acute. The national surveying infrastructure uses two datums (ED50 and TUREF/ITRF96) with two projection conventions (Transverse Mercator with 500,000 m false easting, and 3-degree Gauss-Krüger with zone-prefixed easting), spanning seven central meridians (27° through 45°). This yields 28 possible EPSG codes for projected data, plus UTM variants. A silent wrong CRS shifts data by 100–200 metres — enough to place buildings in the wrong parcel, or a municipal boundary on the wrong side of a river.

The PROJ library formalises coordinate operations as transformation pipelines: chains of elementary steps (inverse projection, datum shift via Helmert or grid, forward projection) each consuming the output of its predecessor [Knudsen & Evers 2017; PROJ Contributors 2024]. The plugin's CRS detector operates before this pipeline, determining the source CRS from drawing metadata and coordinate statistics.

Definition 2 — CRS Ambiguity Problem

Given a set of \(n\) coordinate pairs \(\{(x_k, y_k)\}_{k=1}^n\) drawn from a Turkish survey projection, and optionally a projection text \(T\) from drawing metadata, determine the unique EPSG code \(e^*\) such that the datum (ED50 or TUREF), projection type (TM or GK), and central meridian \(m \in \{27, 30, 33, 36, 39, 42, 45\}\) are correctly identified. The problem is underspecified when \(|T| = 0\) (no metadata) and the easting does not encode the zone (TM form, 6-digit easting), because easting alone cannot determine the central meridian.

Symbology & Cartographic Standards

The visual styling of geospatial data is governed by the OGC Symbology Encoding (SE) standard (OGC 05-077r4), which defines an XML grammar for specifying how features and coverages are portrayed on maps [OGC 2006]. SE describes five symbolizer types — PointSymbolizer, LineSymbolizer, PolygonSymbolizer, TextSymbolizer, and RasterSymbolizer — each applying a graphic (stroke, fill, marker, font) to a feature filtered by OGC Filter Encoding expressions.

The Turkish Ministry of Environment, Urbanisation and Climate Change defines an official symbology catalogue for spatial plans (the e-Plan gösterim kataloğu), encoded as Styled Layer Descriptor (SLD) files served from a GeoServer instance [T.C. ÇŞB 2024]. Each rule in this catalogue specifies, per plan type (UIP 1/1000, NIP 1/5000, CDP 1/25,000+):

The PlanX Adaptive Symbology Engine (PASE) compiles this catalogue offline into symbology-style.db (888 KB, shipped with the plugin) and matches CAD tabaka names against it at import time. The matching algorithm is longest-token-subsequence: a tabaka name is normalised (uppercase, Turkish character mapping, tokenisation) and compared against all catalogue keys, with plan-type fallback (UIP → NIP → CDP). When an official rule is found, it is applied with full fidelity; when none matches, the legacy PASE keyword catalogue provides sensible defaults. A tabaka that matches nothing receives the empty-code-cell policy (cells left blank, upper group set to DİĞER PLAN ALANLARI) rather than an invented code.

CAD vs. GIS Data Models

The semantic gap between CAD and GIS data models has been extensively studied in the context of BIM/GIS integration [Zhu et al. 2018; Sani & Abdul Rahman 2018]. The table below summarises the key structural differences that a converter must bridge.

AspectCAD (DXF/DWG/DGN/NCZ)GIS (GeoPackage/Shapefile/PostGIS)
Geometry modelDrawing primitives: LINE, CIRCLE, ARC, ELLIPSE, SPLINE, TEXT, MTEXT, INSERT (block), POLYLINE, 3DFACE, HATCHOGC Simple Features: Point, LineString, Polygon, Multi* variants. Curved geometries (CircularString, CurvePolygon) only in extended profiles.
Coordinate spaceLocal Cartesian; CRS information is optional, often absent or vendor-specific (e.g. Netcad SRS id, not EPSG).Explicit CRS via EPSG/SRID codes. Every geometry carries its CRS or inherits from the layer.
Layers as semanticsLayers are drawing organisational tools. A single layer may contain points, lines, polygons, and text simultaneously. Functional meaning is encoded in layer names.Layers (feature classes) are homogeneous by geometry type. Meaning is encoded in attribute columns with formal types (integer, real, text, date).
AttributesImplicit: colour (ACI/ARGB), line weight, linetype, layer name, block attributes, extended entity data (XDATA).Explicit: user-defined schema of typed columns, populated per feature. Null values are legal and meaningful.
TextIndependent entities with insertion point, rotation, height, and content. Not linked to any geometry.Labels derived from attribute columns or expressions; rendered by the symbology engine, not stored as geometry.
Blocks / CellsReusable geometry groups inserted at multiple locations with individual scale, rotation, and attributes.No direct equivalent. Must be decomposed into constituent geometries or stored as a related table with point references.
TopologyOptional; polylines may be open or closed by convention. No enforcement of planar partition.Optional but well-supported; topology rules (must not overlap, must not have gaps) are enforceable.

Coordinate Operations and Transformation Accuracy

Coordinate transformation between projected CRS is performed by the PROJ library, which implements geodetic coordinate operations as transformation pipelines: chains of elementary steps (inverse projection → datum transformation → forward projection) that are composed at runtime [Knudsen & Evers 2017]. The accuracy of the transformation depends on the quality of the datum transformation parameters.

In Turkish practice, two datum transformation scenarios are prevalent:

  1. ED50 to TUREF/ITRF96. These datums differ by approximately 180–200 metres over Turkish territory. The transformation requires a 7-parameter Helmert transformation (3 translations, 3 rotations, 1 scale factor) or a grid-based correction. PROJ provides Helmert parameters for ED50-to-WGS84 and ITRF-to-WGS84 chains; the compound ED50-to-TUREF transformation is computed by chaining through WGS 84 as the pivot datum. Grid-based transformations (e.g. using the Turkish national geoid model TG-03) provide higher accuracy but require the grid file to be installed in PROJ's grid directory.
  2. 3-degree TM to 3-degree GK (same datum). These are mathematically equivalent projections differing only in false easting (500,000 m vs. zone × 1,000,000 + 500,000 m). The transformation is a simple easting offset: no datum shift is involved. The plugin handles this by selecting the correct EPSG code for the target CRS rather than computing a coordinate transformation.
\[ \text{ED50} \xrightarrow{\text{Helmert}_{7}} \text{WGS 84} \xrightarrow{\text{Helmert}_{7}^{-1}} \text{TUREF} \]

The plugin's CRS detector avoids the transformation accuracy problem entirely: it identifies the correct source CRS so that PROJ can apply the best available transformation, rather than guessing and potentially applying a wrong or inaccurate shift. When the detector cannot determine the datum with confidence (projection text absent, coordinates in TM form without zone prefix), it leaves the CRS empty rather than assuming TUREF, because a 200-metre error from a wrong datum is far worse than asking the user to verify.

For 2D GIS analysis, the plugin flattens Z coordinates via dropZValue(). Vertical datums (orthometric heights from mean sea level vs. ellipsoidal heights from the reference ellipsoid) are not transformed; Z values are preserved as-is when present, and dropped only when the target GeoPackage layer requires 2D geometry. The GeoPackage standard supports Z and M coordinates in its geometry encoding, but many QGIS analysis tools expect 2D input, making flattening the pragmatic default.

Technical Formulation

Conversion Pipeline Formalization

The 02CadGis conversion pipeline can be expressed as a composition of five transformations. Let a source file \(S\) produce an ordered set of intermediate representations:

\[ S \xrightarrow{\text{read}} \mathcal{L} = \{(L_k, \Gamma_k)\} \xrightarrow{\text{split}} \{(L_k, \Gamma_k^{\text{hom}})\} \xrightarrow{\text{clean}} \{(L_k, \Gamma_k^{\text{simpl}})\} \xrightarrow{\text{transform}} \{(L_k, \Gamma_k^{\text{CRS}})\} \xrightarrow{\text{export}} \text{GeoPackage} \]

where:

Collinear Simplification Algorithm

The collinear simplification implemented in CadCleanupEngine is an iterative greedy algorithm distinct from the Douglas-Peucker polyline simplification [Douglas & Peucker 1973]. While Douglas-Peucker selects a subset of vertices that preserves the line within a perpendicular distance tolerance, the collinear simplifier removes only vertices that lie on or very near the straight line between their immediate neighbours — vertices that contribute no directional information.

Definition 3 — Collinear Vertex

A vertex \(v_i\) in a polyline \(P = (v_0, v_1, \ldots, v_{n-1})\) is collinear with tolerance \(\tau\) if the normalised cross product of the incident edge vectors satisfies:

\[ \sin\theta_i = \frac{|(v_i - v_{i-1}) \times (v_{i+1} - v_i)|}{\|v_i - v_{i-1}\| \cdot \|v_{i+1} - v_i\|} \leq \tau \]

In 2D, \((a_x, a_y) \times (b_x, b_y) = a_x b_y - a_y b_x\). 02CadGis uses \(\tau = 0.02\), corresponding to a deviation angle of approximately \(1.15^\circ\).

The algorithm proceeds iteratively:

Algorithm 1 — Iterative Collinear Simplification
Input:  Polyline vertices P = [v_0, ..., v_{n-1}], tolerance τ
Output: Simplified polyline P'
1.  P' ← copy(P)
2.  if |P'| ≤ 3: return P'
3.  repeat
4.    changed ← False
5.    for i = 1 to |P'|-2:
6.      compute sin θ_i from P'[i-1], P'[i], P'[i+1]
7.      if sin θ_i ≤ τ:
8.        remove P'[i]
9.        changed ← True
10.       break  // restart scan after removal
11. until not changed
12. return P'

This algorithm is \(O(kn)\) where \(k\) is the number of vertices removed (at most \(n-3\)). In practice, CAD drawings contain long straight segments with many intermediate construction points, making this pass highly effective — vertex counts drop by 50–90% on typical municipal plan drawings. The simplification preserves polyline topology: endpoints and true corners (where \(\sin\theta_i > \tau\)) are never removed. A preceding duplicate-removal pass (\(|v_i - v_{i-1}| < 10^{-4}\)) handles co-located construction points.

CRS Detection Logic

The CRS detector in core/crs_detect.py implements a decision procedure combining two independent signals: drawing metadata and coordinate statistics. The procedure is formalised below.

Algorithm 2 — CRS Detection for Turkish Projections
Input:  Projection text T (optional), sample coordinates C = {(x_k, y_k)}
Output: CRS detection result (epsg, label, confidence, reason)

1.  Compute median easting ẽ ← median({|x_k|}) from C
2.  Compute median northing ñ ← median({y_k}) from C
3.  if ẽ ≤ 180 and ñ ≤ 90: return (4326, "high")  // geographic
4.  gk_flag ← ẽ ≥ 1,000,000  // zone-prefixed easting
5.  Parse T: extract datum d (ED50 / TUREF / WGS84 / None)
6.  Parse T: extract zone_width w (3 / 6 / None)
7.  Parse T: extract zone_value z (27..45 or 9..15 or 35..38)
8.  Compute cm ← central_meridian(z, w)
9.  if gk_flag: cm ← int(ẽ / 1,000,000) × 3  // easting overrides text
10. if cm is None and d is None:
11.     if not gk_flag: return ("none", "cannot determine zone from 6-digit easting")
12.     cm ← int(ẽ / 1,000,000) × 3; d ← "TUREF"  // assume modern datum
13. if d is None and not gk_flag: return ("none", "ambiguous datum")
14. epsg ← lookup(d, cm, gk_flag)
15. if ñ ∉ [3,800,000, 4,800,000]: confidence ← "medium"
16. return (epsg, "high" | "medium")

The detector's design philosophy is conservative: when insufficient information exists to name a unique EPSG code, it returns confidence "none" and explains what is missing, rather than guessing. A silent wrong CRS puts data in the wrong place; an explicitly empty CRS forces the user to verify. The northing band check (3.8–4.8M) catches coordinates that are outside Turkey's geographic extent, which typically indicates a non-Turkish projection or a coordinate system error.

NCZ Binary Decoding Methodology

The NCZ Engine v2 employs a two-phase, block-oriented decoding strategy. NCZ files consist of a flat sequence of variable-length blocks, each with a 1-byte kind tag and a 4-byte stored length:

\[ \text{Block}_i = (\text{kind}_i \in [0,255],\; \text{len}_i \in \mathbb{N},\; \text{payload}_i \in \{0,1\}^{8\cdot\text{len}_i}) \]

Phase 1 — Index. The file is scanned once. At each block, if the kind is a known geometry block type (21 or 22), a RecordIndex is created storing the block's absolute position, size, geometry type (byte +6), and layer code (byte +7), without decoding any coordinates. If the kind is a container type ({0, 5, 14, 48, 108, 111, 132, 150, 180}), the payload is scanned for embedded geometry records (recognised by a kind byte 21/22 whose bytes at +5 and +6 are equal, confirming the length-prefix echo pattern). Metadata blocks (kind 6, 25, 28) update the accumulating DrawingMetadata.

Phase 2 — Decode. Records whose layer codes are in the selected set are dispatched to the geometry decoder registry. Decoders are registered by numeric type:

TypeDecoderKey Offsets
1decode_pointPosition at +8/+16 (northing-first f64 pair); name at G+86/+87
2decode_lineStart at +8/+16; end at size-19/size-11
3decode_circleCentre at +8/+16; diameter from +50/+66
4decode_arcCentre at +8/+16; radius at G+86; angles at G+104/+112
5decode_textInsertion at +8/+16; text at G+97/+98; height at G+86
6decode_symbolPosition at +8/+16; code at G+94; size at G+86
7decode_polylineVertex count = (size+1-113-G)/24; vertices at G+113
9decode_compressed_curveOrigin at +8/+16; f32 delta pairs from G+122
10decode_boxCorner at +8/+16; opposite at G+104/+112; rotation at G+120
11decode_map_sheetCorners at +50/+58 and +66/+74
12decode_triangleVertices at +8/+16, +86/+94, +106/+114
13decode_block_referenceInsertion at +8/+16; name at G+86; rotation at G+118
15decode_smart_objectOrigin at +8/+16; width/height at +169/+177; angle at +82 (grads)

Coordinates are stored northing-first (Netcad convention); the QGIS x-coordinate is the second stored f64 value. All reads are bounds-checked by the Cursor class: out-of-range reads return neutral defaults (0, 0.0, empty string) rather than raising, so decoders need no per-field guards. Coordinates outside \([-10^8, 10^8]\) are rejected.

Mojibake Recovery Algorithm

Turkish CAD files suffer from a systematic encoding problem: layer names and text entities containing Turkish characters (ç, ğ, ı, ö, ş, ü and their uppercase forms) are frequently misinterpreted through incorrect codec chains. The term mojibake (Japanese: "character transformation") describes the resulting garbled text.

Three failure modes are common: (a) CAD software writes OEM-codepage bytes (CP1254) that GDAL interprets as UTF-8, producing Latin-1 mojibake; (b) intermediate conversion tools double-encode CP1254 as UTF-8, producing sequences like "PL_KONUT""PL_KÜNÜT"; and (c) DXF files use \U+XXXX Unicode escape sequences that must be unescaped.

Algorithm 3 — Multi-Pass Mojibake Recovery
Input:  Raw text string t
Output: Repaired text string t'
1.  t' ← unescape_dxf(t)  // replace \U+XXXX with chr()
2.  if no mojibake markers in t': return t'
3.  for src in ("latin1", "cp1252"):
4.    for dst in ("utf-8", "cp1254", "iso-8859-9"):
5.      try: t_candidate ← t'.encode(src).decode(dst)
6.      if t_candidate has no mojibake markers: t' ← t_candidate; goto 8
7.      catch: continue
8.  // Direct replacement for stubborn byte sequences
9.  for (bad, good) in REPLACEMENT_MAP:
10.   t' ← t'.replace(bad, good)
11. return t'

The replacement map covers the most stubborn double-encoding patterns: "ç" → "ç", "ö" → "ö", "ü" → "ü", "ÄŸ" → "ğ", "ÅŸ" → "ş", "ı" → "ı", and their uppercase variants. These patterns are the bytewise consequence of CP1254 → UTF-8 double-encoding of Turkish characters and are not naturally occurring in any single encoding.

Geometry Coercion & Type Promotion

CAD layers routinely mix geometry types: a single DXF layer may contain points (text insertion), lines (walls), and polygons (parcels) simultaneously. GIS layers require a single geometry type. The coercion engine resolves this through a hierarchy of conversions:

\[ \begin{aligned} \text{LineString} &\to \text{Polygon}: \text{close the ring if } \|P_0 - P_{n-1}\| \leq \varepsilon_c \\ \text{Polygon} &\to \text{LineString}: \text{extract exterior ring} \\ \text{Point} &\to \text{LineString}: \text{create degenerate 2-point line} \\ \text{Point} &\to \text{Polygon}: \text{point} \to \text{line} \to \text{polygon (if closable)} \\ \text{Single} &\leftrightarrow \text{Multi}: \text{convertToMultiType / convertToSingleType} \end{aligned} \]

3D (Z-bearing) geometries are flattened by calling dropZValue(). Curved geometries (CircularString, CurvePolygon) are segmentized via constrainedStraightSegmentedGeometry(). These operations are applied by _coerce_geometry_for_layer() before features are written to memory layers or GeoPackage, ensuring compatibility with the GDAL GeoPackage driver's geometry type constraints.

GML and XML Namespace Handling

GML (Geography Markup Language) is an XML grammar defined by ISO 19136:2007 and updated in ISO 19136-1:2020 for expressing geographical features. Unlike simpler formats (GeoJSON, KML), GML documents carry XML namespace declarations that associate element names with schema definitions. GDAL's GML driver requires these namespaces to be correctly declared and may fail when they are malformed, incomplete, or reference inaccessible schema URLs [ISO/TC 211 2020].

Common GML interoperability failures include: (a) the gml:id attribute being used as a feature ID when the dataset already has a non-integer fid column, causing GDAL to reject features; (b) application schemas defining custom geometry property names that GDAL does not recognise as spatial columns; (c) xsi:schemaLocation attributes pointing to URLs that no longer resolve, causing validation failures that GDAL treats as fatal. The plugin handles (a) by renaming the conflicting fid column to cadgis_fid in GeoPackage output; (b) and (c) are reported as warnings with guidance on pre-processing the GML with an XSLT transform or schema repair tool.

SpatiaLite and GeoPackage: The SQLite Container Duality

Both SpatiaLite and GeoPackage store geospatial data in SQLite database files, but they use incompatible metadata schemas. SpatiaLite records geometry columns in the geometry_columns table with an srid field referencing spatial_ref_sys, using its own spatial indexing (R*Tree over MBR). GeoPackage records geometry columns in gpkg_geometry_columns with an srs_id referencing gpkg_spatial_ref_sys, using the GeoPackage-specific RTree extension [Yutzler & Daisey 2024].

The plugin reads SpatiaLite files as general SQLite sources through GDAL's SQLite driver (which auto-detects the SpatiaLite metadata tables), but writes output exclusively as GeoPackage. This ensures that output files are readable by any OGC-compliant GeoPackage client, not just QGIS. The CRS is always stored in both EPSG authority form (e.g. EPSG:5257) and as a full WKT definition, satisfying both the GeoPackage standard's requirement for authority-based SRS identification and SpatiaLite's preference for PROJ.4/WKT definitions.

Delimited Text: Type Detection and CRS Inference

The CSV sniffer's type detection logic distinguishes between point geometry (X/Y column pairs), WKT geometry (a column containing Well-Known Text strings), and attribute-only tables (no detected geometry). The detection is a cascade of increasing specificity:

Algorithm 4 — CSV Geometry Column Detection
Input:  Header fields H = [h_0, ..., h_{m-1}], sample data rows S
Output: Geometry profile (x_field, y_field, wkt_field, crs_authid)

1.  // Phase 1: WKT column detection (highest priority)
2.  for each field h_i in H:
3.    if normalize(h_i) in WKT_FIELD_NAMES:
4.      wkt_field ← h_i; break
5.
6.  // Phase 2: Point geometry detection
7.  if wkt_field is empty:
8.    for each field h_i in H:
9.      if normalize(h_i) in X_FIELD_NAMES and column_values_numeric(S, h_i):
10.       x_field ← h_i
11.   for each field h_i in H:
12.     if normalize(h_i) in Y_FIELD_NAMES and column_values_numeric(S, h_i):
13.       y_field ← h_i
14.
15. // Phase 3: CRS inference
16. if x_field and y_field:
17.   if normalize(x_field) in {"lon","long","longitude","boylam"}:
18.     crs_authid ← "EPSG:4326"
19. elif wkt_field:
20.   crs_authid ← ""  // CRS is embedded in WKT or must be user-specified
21. else:
22.   geometry_type ← "none"  // attribute-only table
23. return profile

Numeric validation (_looks_numeric) requires at least one value in the sample to parse as float; a column where all sample values fail to parse is excluded from geometry candidacy. This prevents non-numeric identifier columns from being mistaken for coordinates. CRS inference for point geometry is conservative: only columns with explicitly geographic names (lon/lat/boylam/enlem) receive EPSG:4326; all others leave the CRS unspecified for the user to configure. The WKT path defers CRS detection entirely to the user, since WKT strings may carry their own embedded SRID or may be in any projected system.

CAD Engine

DXF, DWG & DGN Pipeline

The CAD pipeline is: GDAL/OGR read → split by CAD layer → geometry coercion (3D→2D flattening, curve segmentization, single↔multi conversion) → collinear simplification → CRS transform → output.

Layer Splitting & Geometry Coercion

When Split into CAD layers is on, DXF Layer names or DGN Level numbers become separate checkable rows in the layer tree. Geometry coercion handles three compatibility issues: 3D → 2D flattening (Z dropped), curve segmentization (arcs, ellipses, splines → straight segments), and single↔multi conversion (convertToMultiType / convertToSingleType).

Collinear Simplification

The CadCleanupEngine reduces CAD vertex count by 50–90% in two passes: duplicate removal (points within 10−4 map units merged) and collinear removal (iterative — intermediate vertices on straight lines between neighbours are dropped until no more collinear triplets remain). Visual appearance is unchanged; GeoPackage size and render speed improve dramatically.

Typical impact. A straight wall with 20–50 collinear snap-point vertices becomes 2 vertices (endpoints). The geometry is visually identical; the file is proportionally smaller.

AutoCAD DWG: GDAL → ODA → LibreDWG

TierDWG VersionsMechanism
1. GDAL libopencadR2000 and earlierGDAL's built-in CAD driver reads legacy DWG directly.
2. ODA File ConverterR2004–R2024Free CLI tool from Open Design Alliance. Searched in: QSettings, QGIS settings, PATH, environment, Windows registry, common install paths. DWG → DXF via ASCII-safe temp filename → normal DXF read. Interactive setup dialog if not found.
3. LibreDWGVariousOpen-source dwg2dxf fallback when ODA is unavailable.

DGN v8: Pure-Python Reader

When GDAL's DGNv8 driver is absent, the plugin activates its own pure-Python DGN reader: OLE2 compound document → locate element streams → zlib decompress → parse by element type. Line (type 3), LineString (4), and Shape/Polygon (6) are fully supported. Complex containers and annotations contribute Level/colour/style attributes via placeholder geometry. Elements are grouped by DGN Level — same workflow as DXF.

GIS Engine

KML, GML, GeoJSON, CSV & GDB Pipeline

Format-specific pre-processing → OGR read → layer tree → CRS transform → attribute expansion → output. Each format has tailored pre-processing: KMZ is extracted and every KML document inside is read; KML balloon HTML is expanded into real attribute columns; GroundOverlay elements become georeferenced GeoTIFF files; CSV is auto-sniffed for delimiter, encoding, and geometry columns.

CSV/TSV Auto-Detection

The sniffer samples the first 100 lines and determines: delimiter (comma, tab, semicolon, pipe — most consistent column count wins), encoding (UTF-8 → system locale), X/Y columns (header search for x/lon/longitude/easting and y/lat/latitude/northing with numeric range validation), WKT column (header search for wkt/geom/geometry with WKT keyword check), and CRS suggestion (EPSG:4326 when X∈[−180,180] and Y∈[−90,90]). All values are overridable.

KMZ: Multi-Document & GroundOverlay

Standard OGR reads only doc.kml. 02CadGis extracts the entire KMZ and opens every .kml inside. <GroundOverlay> elements are converted to GeoTIFF via their <LatLonBox> bounds and added as raster layers.

Geodatabase: Live Mode & Catalog Cache

Live mode adds checked layers as zero-copy references — data stays in the .gdb/.mdb file; QGIS reads on demand. Benchmarked at ~0.27 seconds for 4.27M features (two layers from a municipal FileGDB). The catalog cache (core/ogr_catalog_cache.py) fingerprints each file (size + mtime) and caches its layer list locally — reopening an unchanged source is 100×+ faster than reopening the driver.

MS Access (.mdb) Reader

When GDAL's PGeo driver is unavailable, a pure-Python reader opens the .mdb as a Jet database, enumerates spatial tables, and reads features into QGIS layers. Requires the 64-bit Microsoft Access Database Engine ODBC driver.

NCZ Engine v2

Engine Architecture

The v2 engine is a ground-up rewrite — an independent, block-oriented Netcad binary decoder with zero dependency on Netcad software. Verified bit-for-bit identical to the previous engine across a synthetic corpus and validated against a real 8,163-entity municipal drawing.

ModuleFileRole
Binary Readerbinary.pyBounds-checked stream. Every read validates offset and length — no buffer overrun possible.
Parserparser.pyFile header, block index, dispatch to decoders by block type.
Geometry Decodergeometry.pyRegistry of decoders per entity type (point, line, polyline, circle, arc, text, block reference, etc.).
Attribute Decoderattributes.pyDecodes @TAB attribute tables stored inside drawings.
Block Catalogueblocks.pyReusable geometry definitions — resolves block references by insertion point, scale, and rotation.

Lazy Catalog & Selective Decode

Selecting a drawing reads only the file header + block index. The layer tree (CAD layer names, entity counts, types) is built from the index — near-instant even for large municipal files. Geometry is decoded only for checked layers at import time. A 50-layer drawing where you need 5 costs only the decode time of those 5.

Fingerprinted Cache (~160×)

Layer catalogs are cached to disk, keyed by absolute path + file size + modification time. Reopening an unchanged drawing shows the layer tree from cache — benchmarked at ~160× faster on a real 1.2 MiB municipal file. Auto-invalidates on file change. Manual reset via "Clear cache" button.

CRS Detection: Turkish Projections

A Netcad drawing stores its own SRS id (e.g. SRS=7936) — this is not an EPSG code. The detector combines two signals:

  1. Projection text → datum (TUREF vs ED50 vs WGS 84) + zone/meridian hint. TUREF and ED50 differ ~200 m over the same ground — coordinates alone cannot distinguish them.
  2. Easting magnitude → axis convention. 6-digit easting (~500,000) = TM form. 8-digit easting (e.g. 3,542,000) = Gauss-Krüger form (zone baked into easting).
FamilyTM Form (EPSG)GK Form (EPSG)Zones
TUREF5253–52595269–527527, 30, 33, 36, 39, 42, 45
ED502319–23252206–221227, 30, 33, 36, 39, 42, 45
WGS 84 / UTM32635–3263835N–38N
ED50 / UTM23035–2303835N–38N
Philosophy: no CRS is better than a wrong CRS. When the drawing lacks enough information, the detector leaves the selection empty and explains what is missing. A silent wrong CRS puts data in the wrong place. The panel also checks that sample coordinates fall within Turkey's northing band (~3.8–4.8M m) — values outside this range indicate a non-Turkish projection.

Batch Import, @TAB Tables & Joins

Multiple NCZ/NCA files can be selected simultaneously. By default, file groups stay separate. Merge geometry types joins layers with the same name across files. @TAB tables (attribute tables stored inside the drawing) are decoded and presented alongside CAD layers; checking both a layer and its matching @TAB performs an automatic attribute join on entity name/label. Optional geometry metrics add length, area, and centroid fields.

PlanGML & Symbology

PlanGML Mode Overview

PlanGML mode (opt-in) transforms a raw CAD drawing into a standards-compliant spatial plan. Three actions occur: (1) tabaka are grouped into the Ministry's official upper groups; (2) PlanGML schema columns are populated from the MPYY UIP database; (3) the official e-Plan symbology is applied — each tabaka drawn with its Ministry-defined fill, stroke, hatch pattern, and label style.

Offline-first. All 350+ gösterim rules and 131 tarama tiles are compiled into the plugin (symbology-style.db, 888 KB). Nothing is downloaded; no style server is needed. The gösterim is the official standard, not 02CadGis artwork — see THIRD_PARTY_NOTICES.md.

UIP Tabaka Catalog & Upper Groups

The catalog maps 256 official tabaka to their hierarchy. A documented alias list resolves local municipal spellings onto the official tabaka they represent. Tabaka not in the catalog get empty code cells (not invented codes) and go to DİĞER PLAN ALANLARI — deliberately the only group name not from the Ministry's catalog.

350+ Gösterim Rules & Tarama

The PlanX Adaptive Symbology Engine (PASE) matches each tabaka against the official e-Plan catalog. Each rule specifies: fill colour, stroke, hatch pattern, tarama tile path, plan type applicability (UIP 1/1000, NIP 1/5000, CDP 1/25,000+). The plan type is auto-detected from the file name and can be overridden.

PlanGML Attribute Schema

When PlanGML mode is on, each feature receives 16 official columns: UST_GRUP_ID, UST_GRUP_ADI, ALT_GRUP_ID, ALT_GRUP_ADI, DETAY_GRUP_ID, PLAN_KODU, FONKSIYON_KODU, LEJANT_KODU, KOD, TAM_ADI, GISTERIM, GUSTERIM_ADI, LEJANT, FONKSIYON, KULLANIM, and uip_tabaka (the drawing's original tabaka name, always preserved).

Adaptive Tabaka Matching Algorithm

The PlanX Adaptive Symbology Engine (PASE) uses a longest-token-subsequence matching strategy that is robust to the variations in tabaka naming encountered in real municipal drawings. A tabaka name like "1000_UIP_PL_KONUT_ALANI_POLYGON" must be matched to the official catalogue entry for "PL_KONUT" despite the scale prefix, plan type prefix, geometry type suffix, and Turkish character variations.

The matching algorithm proceeds in four tiers of decreasing specificity:

  1. Tier 1 — Official e-Plan catalogue (longest-token-subsequence). The layer name is normalised (uppercase, Turkish-to-ASCII mapping Ç→C, Ğ→G, İ→I, Ö→O, Ş→S, Ü→U, non-alphanumeric to underscore, leading scale/plan-type prefixes stripped), then tokenised on underscores. All catalogue keys (also tokenised) are sorted by decreasing token count and decreasing key length for longest-first priority. Matching checks whether all tokens of a catalogue key appear as a contiguous subsequence in the layer name tokens. When a match is found for the requested plan type, that entry is used; when the token is missing for the requested plan type, the fallback chain (UIP → NIP → CDP or NIP → UIP → CDP or CDP → NIP → UIP) reuses the closest official equivalent.
  2. Tier 2 — Attribute-based matching. If the layer carries PlanGML schema columns populated from a previous import, PASE checks the PLAN_KODU, FONKSIYON_KODU, and LEJANT_KODU fields against the keyword lists of the legacy PASE catalogue. This tier handles re-imported or enriched layers where the tabaka identity is already known.
  3. Tier 3 — Exact tabaka name match (legacy PASE catalogue). The raw layer name (with Turkish characters normalised) is compared verbatim against every keyword in the legacy catalogue. Both direct match and "PL_"-prefixed variants are tried, because some municipalities use "KONUT" while others use "PL_KONUT" for the same function.
  4. Tier 4 — Substring keyword match (legacy PASE catalogue). Normalised tokens from the layer name are checked against normalised keywords. A single matching token is sufficient for a match, so "YESIL_ALAN" matches the "YESIL_ALAN" keyword even if the full layer name is "1000_UIP_ACIK_VE_YESIL_ALANLAR".
  5. Tier 5 — Default fallback. A neutral grey fill with medium opacity and the upper group DİĞER PLAN ALANLARI. The original tabaka name is preserved in all columns that store it, so downstream analysis can filter and reclassify.

Two-Stage Hybrid Rendering Pipeline

Symbology application uses a two-stage strategy that chooses between categorised and single-symbol rendering based on the data content:

Stage 1 — Categorised renderer. If the layer has a field from the PlanGML schema candidate list (uip_tabaka, ALT_GRUP_ADI, TAM_ADI, GISTERIM, etc.) that contains 1–300 unique values, a QgsCategorizedSymbolRenderer is created. Each unique value is independently matched against the symbology catalogues, producing a symbol that reflects that specific tabaka's official appearance. A single-tabaka layer is still categorised (1 category) because the single-value path correctly resolves the tabaka's official symbol, whereas the fallback single-symbol path (Stage 2) matches against the layer name, which for official upper-group names (e.g. "SU_ATIKSU_VE_ATIK_SISTEMLERI") does not contain any keyword and would render grey. This behaviour was corrected in v2.8.1.

Stage 2 — Single-symbol renderer. Applied when no suitable category field exists. The layer name is matched against the catalogues. For polygon layers, the symbol is a multi-layer fill symbol consisting of (a) an optional background fill with the official colour, (b) optional vector hatch pattern layers (one for diagonal/cross patterns, two for cross hatch with perpendicular angles), and (c) a clean outline layer with the official stroke colour and dash style. For official e-Plan rules with tarama tiles, the fill layer is replaced by a QgsRasterFillSymbolLayer rendering the Ministry's pattern image at its native pixel size. For line layers, the symbol respects the official dash pattern vector (e.g. [12, 4, 2, 4] from the SLD) via setCustomDashVector.

Text labelling uses the pick_label_field function, which probes candidate field names ("label", "label_text", "text", "yazi", "kat_adedi", "emsal", etc.) and accepts a candidate only when at least one non-empty value has been observed in the layer. This prevents binding labels to a column that exists but is empty on all features — a failure mode that previously produced silently blank labels. Point layers that carry text render with a subtle 0.6 mm anchor marker so the text's insertion point is visible without competing with the label content.

Parameters

CAD Engine Parameters

ParameterTypeDefaultDescription
Split into CAD layersbooleanTrueWhen enabled, each DXF Layer name or DGN Level number becomes a separate checkable row in the layer tree. When disabled, all entities appear as a single layer.
Collinear simplificationbooleanTrueApply CadCleanupEngine: duplicate vertex removal (< 10−4 map units) followed by iterative collinear vertex removal (cross-product tolerance 0.02). Reduces vertex count 50–90% with no visible geometry change.
Close polylinesbooleanFalseWhen enabled, polylines whose first and last vertices are within 0.0001 map units are closed into polygons. Useful for CAD drawings where parcels or building footprints are drawn as open polylines.
Polyline closure tolerancefloat (map units)0.01Maximum gap between polyline endpoints that triggers automatic closure to a polygon. Larger values close more aggressively but may incorrectly close intended open lines.
ODA File Converter pathfile path(auto-detected)Path to ODAFileConverter.exe for modern DWG (R2004+) conversion. Auto-detected from QSettings, QGIS settings, PATH, Windows registry, and common install locations. Interactive setup dialog offered if not found.
DWG target version for ODAstring"ACAD2018"Target DXF version for ODAFileConverter. Fallback chain: ACAD2018 → ACAD2013 → ACAD2010 → ACAD2000. Each version is tried in sequence until conversion succeeds.

GIS Engine Parameters

ParameterTypeDefaultDescription
Expand KML HTML descriptionsbooleanTrueParse HTML tables and list items from KML <description> balloon content into real attribute columns. Both <tr><td> and <li><b>key</b>: value</li> patterns are recognised.
Extract GroundOverlay rastersbooleanTrueConvert KML <GroundOverlay> elements to georeferenced GeoTIFF raster layers. Each overlay's <LatLonBox> bounds define the geotransform; CRS is EPSG:4326.
CSV delimiterstring(auto-detected)Field delimiter for CSV/TSV files. Auto-detected from {,, ;, \t, |} by Python's csv.Sniffer with majority-consistency tiebreaking. Manual override available.
CSV X field / Y fieldfield name(auto-detected)Column names for point geometry coordinates. Auto-detected by matching header field names against known X/Y candidates (x/lon/longitude/easting/boylam/saga and y/lat/latitude/northing/enlem/yukari) with numeric value validation.
CSV WKT fieldfield name(auto-detected)Column name for WKT geometry. Auto-detected from wkt/geometry/geom/the_geom/shape/wkt_geom.
CSV source CRSEPSG code(auto-detected)Source CRS for CSV geometry. Auto-set to EPSG:4326 when coordinate field names suggest geographic coordinates (lon/lat). Manual override available.
CSV encodingstringutf-8-sigFile encoding. Read with BOM detection (utf-8-sig); errors are replaced rather than raised.
GDB/MDB Live modebooleanFalseLoad selected layers as zero-copy references instead of converting to GeoPackage. No conversion time or disk space; CRS transformation is not applied. Ideal for browsing large geodatabases.
OGR catalog cachebooleanTrueCache multi-layer source catalogs (GDB, MDB, SQLite) locally, keyed by file fingerprint (size + mtime). Controlled by ZERO2CADGIS_OGR_CACHE_DISABLE environment variable.

NCZ Engine Parameters

ParameterTypeDefaultDescription
Merge geometry typesbooleanFalseWhen importing multiple NCZ files, merge layers sharing the same name across files into single output layers. When disabled, each file's layers stay separate with file-name prefixes.
Apply PlanGML schemabooleanFalsePopulate the 16-column PlanGML attribute schema for each feature. Matches tabaka names against the official MPYY UIP catalog. Empty cells for unrecognised tabaka (no code invention).
Apply PlanGML symbologybooleanFalseApply the official e-Plan gösterim symbology (fill, stroke, hatch, tarama tile, label) via the PlanX Adaptive Symbology Engine. Sourced from the compiled symbology-style.db.
Plan typeenumAUTOSelects the official style set: UIP (1/1000), NIP (1/5000), CDP (1/25,000+), or AUTO (inferred from file/layer name). Controls which plan-type-specific gösterim rules are applied. Falls back through UIP → NIP → CDP when a token is missing for the selected type.
Calculate geometry metricsbooleanFalseAdd geom_len, geom_area, cent_x, cent_y columns computed from each feature's geometry. Length and area are in target CRS units; centroids are point coordinates.
Import @TAB attribute tablesbooleanTrueDecode @TAB attribute tables embedded in the NCZ file. Tables are presented as checkable rows in the layer tree alongside CAD layers. Checking both a layer and its @TAB performs automatic join on entity name.
NCZ index cachebooleanTrueCache the decoded drawing metadata, layer catalog, and attribute tables locally (JSON, per-user cache directory). Keyed by SHA-256 of absolute path + (size, mtime_ns) fingerprint. Controlled by ZERO2CADGIS_NCZ_CACHE_DISABLE.
NCZ selective decodebooleanTrueDecode geometry only for checked layers (v2 engine). Unchecked layers contribute zero decode time. When disabled, all records are decoded (v1-compatible full-parse mode).
CAD colour stylingbooleanTrueApply ARGB colours from the NCZ drawing to output layers as categorised QGIS renderers. When disabled, layers use default QGIS styling. NCZ colour codes: 0 = by layer, 1 = forced blue, 255 = forced red; layer colours come from LEX.ST2 block.

Output & Export Parameters

ParameterTypeDefaultDescription
Output modeenumGeoPackageOne of: GeoPackage (permanent .gpkg, CRS transform applied), Scratch (temporary memory layer, CRS transform applied), Live (zero-copy reference, no CRS transform, for GDB/MDB only).
Target GeoPackagefile path(user-selected)Destination .gpkg file. Created if absent; layers are added with CreateOrOverwriteLayer semantics. Existing layers with the same name are replaced.
Target CRSCRS(project CRS)Target coordinate reference system for GeoPackage and Scratch output modes. Source coordinates are transformed via QgsCoordinateTransform using the PROJ pipeline.
Export formatenumDXFExport format for the exporter panel: DXF (via QgsVectorFileWriter, attributes skipped), KML, or KMZ (KML zipped as doc.kml with DEFLATE compression).
DXF preserve layer namesbooleanTrueWrite QGIS layer names as DXF layer names to preserve organisational intent for CAD collaborators.
KML/KMZ name fieldfield name"name"Attribute column used as the KML <name> element for each exported feature.
KML/KMZ description fieldfield name"description"Attribute column used as the KML <description> element for each exported feature.

Output, Export & Styling

GeoPackage, Scratch & Live

ModePersistenceCRS TransformBest For
GeoPackagePermanent .gpkgYesDurable deliverables, data exchange, archival
ScratchTemporary memory layerYesQuick inspection, "try before you commit"
LiveZero-copy referenceNoBrowsing large GDB/MDB. No conversion time or disk space.

DXF / KML / KMZ Export

The exporter panel writes any active QGIS vector layer to DXF, KML, or KMZ via QgsVectorFileWriter. DXF preserves layer names and colour intent for CAD collaborators.

CAD Colors, Labels & Mojibake Repair

Netcad ARGB colours are preserved via categorised renderers (one symbol per colour). Text labels select a column that actually contains text (not merely exists while empty). Point layers with text draw a subtle 0.6 mm anchor. The mojibake repair engine applies multi-pass encoding recovery: UTF-8 → CP1254 → CP1252 → ISO-8859-9 → direct character replacement map for stubborn byte sequences. Applied to layer names, attributes, labels, and UI tree items. DXF \U+XXXX escapes are also unescaped.

Interpretation Guide

DXF / DWG Workflow

Step 1: Source selection. Drag a .dxf or .dwg file onto the dock, or click "Browse" on the CAD & GIS Converter tab. For DWG R2004+, the plugin searches for ODA File Converter; if not found, an interactive setup dialog guides installation from opendesign.com. Once configured, the file opens and the layer tree populates.

Step 2: Layer tree inspection. With "Split into CAD layers" enabled (default), each DXF Layer name becomes a row showing its geometry family and feature count. Uncheck layers you do not need — this eliminates their conversion time. The tree is built from GDAL's OGR driver, which reads the header only; feature counts may be −1 (unknown) for large files until conversion begins.

Step 3: Configure options. Keep "Collinear simplification" on unless you need exact vertex-level fidelity (e.g. for legal cadastral boundaries where every vertex matters). The "Close polylines" option is useful when CAD polylines represent parcels or building footprints but were drawn open. Set the tolerance conservatively (0.01–0.05 map units).

Step 4: CRS. DXF/DWG files carry no explicit CRS. The plugin attempts auto-detection from coordinate magnitudes, but in most cases you must select the CRS manually. If the coordinates look like projected values (6–8 digit eastings, 7-digit northings), select the appropriate projected CRS. If the drawing is in arbitrary local coordinates, convert without CRS and georeference later.

Step 5: Output. Choose GeoPackage for durable output or Scratch for quick inspection. Click "Convert". Output layers appear in the QGIS layer tree with CAD colours applied and mojibake-repaired names.

DWG performance note. All three DWG tiers (GDAL, ODA, LibreDWG) produce a temporary DXF intermediate. The ODA File Converter is the most reliable for modern files. LibreDWG is the slowest but requires no proprietary software. GDAL libopencad works only for legacy R2000 and earlier.

DXF Layer Name Conventions

DXF layer names in Turkish planning practice follow several common conventions that affect how they appear in the layer tree. Understanding these conventions helps in deciding whether to split by layer and which layers to import:

DGN Level Number Mapping

MicroStation DGN files use numeric levels (1–63 in older versions, up to 65,535 in v8) rather than named layers. When the GDAL DGNv8 driver is available, level names from the DGN's level table are displayed alongside numbers, e.g. Existing Buildings (Level 12). When using the pure-Python fallback reader, level names are extracted from the DGN's named level table if present; otherwise, only level numbers are shown. The plugin groups entities by level exactly as it groups DXF entities by layer name, making the workflow identical once the source is opened.

Handling Large CAD Files

For DXF files exceeding 50 MB or with more than 100 layers:

  1. Use the layer tree to uncheck all layers, then check only the 5–10 layers you need. This dramatically reduces conversion time because GDAL reads and filters at the driver level.
  2. Disable collinear simplification if you need every vertex (e.g. for legal cadastral boundaries). For visualisation and analysis, keeping it enabled reduces output file size by 50–90%.
  3. Use Scratch mode for first inspection — it creates temporary memory layers with no file I/O overhead. Once you've verified which layers contain useful data, re-import to GeoPackage with only those layers checked.
  4. For DWG files, the ODA File Converter step adds 5–30 seconds depending on file complexity. This cost is paid once per file; the converted DXF is cached in a temp directory and reused for subsequent imports.

DGN Workflow (Detailed)

DGN files require special attention because the GDAL build shipped with standard QGIS does not include the DGNv8 driver. The pure-Python fallback reader handles most planning-grade DGN files but has limitations that affect workflow decisions.

Step 1: Determine whether the fallback reader is needed. If GDAL opens the DGN file successfully (the layer tree shows non-zero feature counts for at least one layer), the GDAL driver is handling the file and full fidelity is available. If GDAL returns zero layers or 0 features, the pure-Python reader activates automatically. The plugin logs which reader is active.

Step 2: Understand fallback reader limitations. The pure-Python reader supports line (type 3), linestring (type 4), and shape/polygon (type 6) elements. Complex cell geometry, text elements as full text (not placeholder points), dimension elements, and custom line styles are not rendered as full geometry. These entities contribute placeholder points with their level, colour, weight, and style attributes preserved. If your workflow requires these element types as full geometry, convert the DGN to DXF using Bentley MicroStation or ODA Drawings Explorer (both free for viewing/conversion) before importing.

Step 3: Polygon detection. The reader classifies shape elements (type 6) as polygons when their vertex ring is closed (first and last points coincident within 10−6 map units). Open shape elements are imported as polylines. If your DGN uses open shapes to represent parcels or building footprints (a common MicroStation convention), those elements will import as lines. Enable "Close polylines" in the CAD options to auto-close them within the specified tolerance.

Step 4: Coordinate filtering. The fallback reader validates coordinates against realistic bounds: x and y must each be in [100,000, 16,000,000] and the absolute difference between x and y must be at least 1.0. This filters degenerate point clouds and corrupted elements. Elements entirely outside these bounds are skipped with a logged count. If legitimate data is being filtered (e.g. very small-scale regional maps with coordinates near the origin), check the coordinate system and consider adjusting the source.

GML and GeoJSON Workflow

GML and GeoJSON are both text-based OGC standard formats but have very different performance and usability characteristics in the conversion pipeline.

GML approach. GML files are XML documents that GDAL parses into a DOM before reading features. For files larger than 50 MB, this DOM construction can be slow and memory-intensive. Strategy: (a) if the GML contains many feature types, uncheck the ones you do not need to reduce the feature count; (b) if GDAL reports schema validation errors, the GML's xsi:schemaLocation URLs may be unreachable — try editing the GML header to remove or fix these URLs; (c) GML files carrying a fid attribute with non-integer values will have that column renamed to cadgis_fid in the output GeoPackage to avoid conflicting with the GeoPackage primary key.

GeoJSON approach. GeoJSON is simpler: it is a single JSON object with a features array. GDAL reads it efficiently, but RFC 7946 mandates WGS 84 (EPSG:4326). If your GeoJSON uses an alternative CRS (a legacy convention), GDAL reads the CRS from the crs member if present. Always verify the CRS after import: if the coordinates look like projected values (6–8 digit eastings) but the layer CRS is EPSG:4326, the GeoJSON was written with non-standard CRS and the coordinates were not reprojected. In this case, manually set the source CRS to the correct projected system and re-import.

NCZ / NCA Workflow

Step 1: File selection. Switch to the "Netcad NCZ/NCA Importer" tab. Use "Select Files" to choose one or more .ncz/.nca files. The plugin indexes each file (reading only the header + block index) and displays its metadata: version, projection text, SRS id, layer count, and entity count. With the v2 index cache enabled, reopening an unchanged file shows this instantly.

Step 2: CRS detection. The projection text is parsed, sample coordinates are read, and the detector proposes an EPSG code with a confidence level and explanation. Green (high confidence) means both datum and zone are certain. Yellow (medium confidence) means one signal is missing (typically the datum — TUREF is assumed for modern data). Red (none) means neither signal is sufficient; you must select manually. Always verify the proposed CRS against your knowledge of the data.

Step 3: Layer selection. The layer tree shows each CAD layer by code, name, record count, and geometry families. Check only the layers you need. @TAB tables appear alongside layers; checking both a layer and its @TAB performs the automatic join. Use "Select All" / "Deselect All" for bulk operations.

Step 4: PlanGML (optional). Enable both "Apply PlanGML schema" and "Apply PlanGML symbology" for planning data. Select the plan type (AUTO usually works, inferring from scale prefixes in the file name). The plugin populates the 16-column schema and styles each feature per the official e-Plan catalogue.

Step 5: Batch options. When importing multiple files, decide whether to merge same-named layers across files ("Merge geometry types") or keep them separate. Geometry metrics (geom_len, geom_area, cent_x, cent_y) are useful for quality checking but add processing time.

KML / KMZ Workflow

Step 1: Source. Drag a .kml or .kmz file onto the dock. KMZ archives are fully extracted; all .kml documents inside are enumerated (not just doc.kml). Multi-document KMZ files have each document's layers prefixed with the document stem to prevent name collisions.

Step 2: Layers. The layer tree shows each KML folder/feature class as a row. KML sources typically carry EPSG:4326 (WGS 84 geographic). Enable "Expand HTML descriptions" to parse balloon content into attribute columns. Enable "Extract GroundOverlay rasters" for aerial imagery or scanned maps embedded as overlays.

Step 3: Output. Choose GeoPackage with a projected target CRS if you need metric geometry for analysis. KML's native geographic coordinates will be transformed. GroundOverlay rasters are written as separate GeoTIFF files in the same directory as the KML source.

GDB / MDB Workflow

Step 1: Source. Select a .gdb directory (File Geodatabase) or .mdb file (Personal Geodatabase / MS Access). The OGR catalog cache makes reopening instant after the first inspection.

Step 2: Mode choice. For browsing, use Live mode: layers load as zero-copy references in ~0.27 seconds regardless of size. For durable deliverables or CRS transformation, use GeoPackage mode. Live mode preserves the source CRS; if you need reprojection, you must use GeoPackage or Scratch.

Step 3: MS Access fallback. If GDAL's PGeo driver cannot open the .mdb, the plugin's pure-Python MS Access reader activates (requires 64-bit Microsoft Access Database Engine ODBC driver). It enumerates spatial tables via pyodbc and reads features directly.

GDB version compatibility. GDAL's OpenFileGDB driver reads File Geodatabases version 9 and 10. Very old (pre-9) or very new (Esri proprietary extensions) GDBs may fail. The plugin reports a clear error with troubleshooting guidance.

CSV / TSV Workflow

Step 1: Source. Select a .csv, .tsv, or .txt file. The sniffer samples the first 100 lines and auto-detects delimiter, fields, point geometry columns, WKT column, and CRS.

Step 2: Verify detection. Review the auto-detected settings in the UI. The delimiter, X/Y fields, WKT field, geometry type, source CRS, and encoding are all overridable. If the sniffer misidentifies a column, correct it before conversion. The geometry summary line ("Point from 'longitude' / 'latitude'" or "WKT column 'geometry'") confirms what will be imported.

Step 3: Output. Delimited text with point geometry writes a Point layer. WKT geometry preserves whatever type the WKT strings describe (Point, LineString, Polygon, etc.). Files with no detected geometry become attribute-only tables. All output goes to the selected GeoPackage.

Large CSV note. The sniffer reads only the first 256 KB of the file. If your geometry columns appear after this prefix, the sniffer will not detect them. Select them manually in the override fields.

PlanGML Workflow

Step 1: Prerequisites. PlanGML mode requires an NCZ drawing whose tabaka names follow the MPYY convention (e.g. PL_KONUT, PL_PARK, PL_YOL). Drawings using arbitrary local naming will have unrecognised tabaka routed to DİĞER PLAN ALANLARI with empty code cells.

Step 2: Enable. On the NCZ Importer tab, check both "Apply PlanGML schema" and "Apply PlanGML symbology". Verify the auto-detected plan type. For files named like 1000_BAHCESARAY_IMAR.ncz the plan type will be detected as UIP.

Step 3: Output verification. After conversion, each feature has 17 columns (16 PlanGML + uip_tabaka). The symbology is applied as a QGIS categorised renderer on the uip_tabaka field when multiple tabaka are present, or a single-symbol renderer for single-tabaka layers. Hatch patterns (tarama) render via raster fill symbol layers at the Ministry's native pixel resolution.

Troubleshooting

SymptomLikely CauseRemedy
DWG file fails to openModern DWG (R2004+) with no ODA File Converter availableInstall ODA File Converter from opendesign.com. The plugin's setup dialog guides this. Alternatively, convert the DWG to DXF in AutoCAD or a free viewer.
DGN file opens but returns 0 featuresDGN v8 file; GDAL build lacks the DGNv8 driver (requires ODA Teigha)The plugin's pure-Python DGN reader activates automatically. If it also fails, convert to DXF using Bentley MicroStation or ODA Drawings Explorer.
NCZ data appears in the wrong locationWrong CRS selected. Common error: SRS id (e.g. 7936) used as EPSG code.The SRS id is not an EPSG code. Use the auto-detected CRS or manually select the correct projected CRS for your region. Verify a few known point coordinates after import.
Turkish characters garbled (e.g. PL_KÜNÜT instead of PL_KONUT)Mojibake: CP1254 bytes decoded as UTF-8 by intermediate tool or GDALThe plugin's mojibake repair engine runs automatically. If some strings remain garbled, the layer name or attribute was corrupted beyond the known recovery patterns. Rename manually in QGIS.
KML GroundOverlay images not georeferencedKML uses <Icon><href> with a relative path that cannot be resolvedEnsure the image file is present in the same directory as the KML. The plugin checks both relative path (including subdirectories) and basename-only fallback.
CSV imports with wrong delimiter or no geometryFirst 100 lines are header/metadata; data structure differs afterwardOverride the auto-detected settings manually. Specify delimiter, X/Y or WKT columns, and CRS explicitly.
GDB/MDB fails with "Unable to open"Missing ODBC driver for .mdb; incompatible GDB version; file locked by another processFor .mdb: install 64-bit Microsoft Access Database Engine. For .gdb: ensure no other process (ArcGIS, ArcCatalog) has the GDB open. Try copying the GDB directory and opening the copy.
GeoPackage conversion succeeds but feature count is lower than expectedFeatures with no geometry (NULL geometry) are filtered. Empty geometries are skipped.This is by design. Check the plugin's warning log for the count of skipped features. If many features were dropped, inspect the source in its native application to verify geometry presence.
PlanGML symbology shows grey (default) for a known tabakaThe tabaka name does not match any keyword in the official or legacy cataloguesCheck the exact spelling (including underscores, Turkish characters) against the catalog. If the tabaka is genuinely missing, it receives the DİĞER PLAN ALANLARI group with a neutral grey fill. The original tabaka name is preserved in uip_tabaka.
Conversion is slow for a large fileAll layers are selected for conversion; collinear simplification is heavy on very complex polylinesUncheck layers you do not need. The NCZ v2 engine decodes only checked layers. For GDAL-based formats, use Live mode first to inspect the data, then convert only the layers you need.

Performance Characteristics

The plugin employs a layered caching architecture to minimise repeated work on large datasets. Performance is characterised across three access patterns.

Cold Open (First Access)

On first access, the file must be parsed or opened through the appropriate driver. The dominant cost is I/O, not computation; therefore the plugin reads only what is necessary to build the layer tree. For NCZ drawings, the v2 engine reads just the file header and block index (Phase 1); geometry decoding (Phase 2) is deferred until import. For OGR-based formats, ogr.Open() is the unavoidable cost, but the catalog cache eliminates it on subsequent accesses. For CSV/TSV, the sniffer reads only the first 256 KB to determine structure.

FormatTypical Cold OpenWhat Is ReadBottleneck
NCZ (1.2 MiB, 8163 entities)~15 ms (index only)Block headers + metadataSequential file read
NCZ full decode (same file)~160 msAll geometry coordinatesf64 unpacking + dict construction
DXF (< 10 MiB)~1–3 sFull text parse by GDALGDAL DXF driver text processing
FileGDB (municipal, 4.27M features)~2–5 s (catalog)Table directory scanFile count walk in .gdb directory
KML/KMZ (< 50 MiB)~0.5–2 sFull XML parse by GDALXML DOM construction
CSV/TSV (any size)~0.1–0.3 sFirst 256 KB onlycsv.Sniffer heuristics

Warm Reopen (Catalog Cache Hit)

Reopening an unchanged file loads the layer catalog from the fingerprinted JSON cache. No driver is opened; no bytes are read from the source file. The NCZ index cache achieves ~160× speedup on a real 1.2 MiB municipal file (from ~15 ms to ~0.1 ms). The OGR catalog cache achieves 100×+ speedup on multi-layer geodatabases by avoiding ogr.Open() entirely. Cache invalidation is automatic on file size or modification time change; manual invalidation is available through the dock's "Clear cache" button and the ZERO2CADGIS_NCZ_CACHE_DISABLE / ZERO2CADGIS_OGR_CACHE_DISABLE environment variables.

Selective Import

The lazy catalog enables a decode-what-you-need strategy. Checking only 5 of 50 layers in an NCZ drawing decodes only those 5 layers' geometry records — about 10% of the file's entity count. Benchmark shows ~3.4× speedup over full decode for 1 of 5 layers. For GDAL-based CAD formats, the subset string ("Layer" = 'BUILDINGS') is pushed down to GDAL, which filters at read time.

Cross-Format Comparison

The table below summarises structural differences that affect conversion behaviour across the supported formats.

PropertyDXF/DWGDGN v8NCZ/NCAKML/KMZGeoJSONGMLCSV/TSVGDB/MDB
CRS in fileNoOptionalPartial (SRS id + projection text)Yes (WGS 84)Yes (WGS 84)YesNoYes
Geometry types per layerMixedMixedMixedHomogeneousHomogeneousHomogeneousOne typeHomogeneous
AttributesImplicit (Layer, colour, linetype)Implicit (Level, colour, weight, style)Implicit + @TAB tablesExplicit (HTML description, schema)Explicit (properties object)Explicit (feature-member properties)Explicit (column headers)Explicit (field definitions)
Text supportNative entitiesNative elementsNative entities (Type 5)Placemark name/descriptionProperties onlyProperties onlyColumn valuesField values
3D geometryYes (Z coordinates)Yes (3D elements)Yes (Z per vertex)Yes (altitudeMode)Yes (Z in coordinates)Yes (3D geometry types)Optional (Z column)Yes (Z-enabled)
Curve supportYes (ARC, ELLIPSE, SPLINE)Yes (curve elements)Yes (ARC type 4, compressed curve type 9)No (segmentized)NoYes (Curve, ArcString)NoOptional (CAD-only)
Block/cell supportYes (INSERT)Yes (shared cells)Yes (BlockRef type 13, SmartObject type 15)NoNoNoNoNo
Multi-file supportSingle fileSingle fileMultiple files (batch)KMZ: multi-KML archiveSingle fileSingle fileSingle fileDirectory-based (GDB)
Live modeNoNoNoNoNoNoNoYes
Export supportedDXFNoNoKML, KMZNoNoNoNo

Encoding Recovery & Text Handling

Character Encoding in CAD Files

CAD systems and their exchange formats handle text encoding with varying degrees of rigour. The most severe problems arise in Turkish-language CAD data, where the Turkish alphabet introduces six characters (ç, ğ, ı, ö, ş, ü) not present in ASCII or ISO 8859-1 (Latin-1). The encoding chain from CAD authoring to QGIS display involves multiple transcoding steps, each of which can introduce corruption.

DXF files nominally use the system code page of the authoring machine. Turkish Windows uses code page 1254 (Turkish), but DXF readers often default to ASCII or Latin-1. DXF \U+XXXX Unicode escape sequences can represent any Unicode character but are not universally supported by GDAL's DXF driver. Netcad NCZ files store text in an OEM byte mapping that maps Turkish characters to non-standard byte values (221 → İ, 222 → Ş, 208 → Ğ, etc.).

The mojibake repair engine in core/qgis_compat.py addresses these systematically through a three-stage recovery pipeline:

  1. DXF unescape — regex replacement of \U+XXXX and \u+XXXX patterns with the corresponding Unicode character via chr(int(hex, 16)). This handles CAD software that writes Turkish characters as escapes rather than encoding them in the code page.
  2. Encoding round-trip recovery — for each detected mojibake pattern (Latin-1 characters in the range 0xC0–0xFF that form plausible double-encoding signatures), the engine tries encoding to Latin-1 or CP1252 and decoding as UTF-8, CP1254, or ISO-8859-9. The first candidate that eliminates all known mojibake markers is accepted.
  3. Direct byte-pattern replacement — a fixed mapping of 8 stubborn byte sequences ("ç" → "ç", etc.) that survive the round-trip recovery because the original encoding chain was more than two steps deep. These patterns are exhaustive for the CP1254 → UTF-8 double-encoding of all six Turkish characters plus their uppercase forms.
Encoding provenance. The OEM byte values for Turkish characters in NCZ files (221, 222, 208, 240, 253, 254) are documented in docs/NCZ_FORMAT.md and verified against real municipal drawings. The CP1254/CP1252/UTF-8 mojibake patterns were collected empirically from hundreds of real CAD files and verified by reversible encoding/decoding test cases.

Caching Architecture

The plugin implements two independent, fingerprinted on-disk caches for different data sources, sharing a common design but specialised for their respective access patterns.

NCZ Index Cache

Stores a drawing's decoded metadata (DrawingMetadata), per-layer catalog summaries, and decoded @TAB attribute tables as JSON. The cache key is SHA-256 of the absolute file path; invalidation uses a (size, mtime_ns) fingerprint plus CACHE_VERSION. Cache files live under %LOCALAPPDATA%/zero2cadgis/ncz_index/ (Windows) or $XDG_CACHE_HOME/zero2cadgis/ncz_index/ (Linux).

On a cache hit, the dock builds the layer tree without opening the NCZ file at all. Geometry is still decoded from the file at import time (Phase 2), so the cache never stores coordinate data — it is purely a metadata accelerator. Atomic writes (write to .tmp, then os.replace) prevent corruption on concurrent access.

OGR Catalog Cache

Stores multi-layer OGR source catalogs (layer names, geometry types, feature counts) as JSON. For directory-based datasets (File Geodatabase .gdb), the fingerprint aggregates file count, total byte size, and newest modification time across up to 4096 entries (to keep the stat walk cheap). For single-file datasets (.mdb, .sqlite, .gml), the fingerprint is simply (size, mtime_ns).

The OGR catalog cache is critical for multi-layer geodatabases where ogr.Open() on a large .mdb or .gdb takes several seconds just to enumerate layers. With a warm cache, the layer list appears instantly, and the driver is only opened when the user initiates conversion.

GDAL/OGR Driver Fallback Chain

Not all GDAL builds include all drivers. Standard OSGeo4W QGIS builds ship with the CAD (DXF), KML, GML, GeoJSON, GPKG, SQLite, OpenFileGDB, and CSV drivers, but may lack the PGeo (Personal Geodatabase), DGNv8, or libopencad (DWG) drivers. The plugin detects missing drivers and activates its own readers:

FormatGDAL DriverAvailability in Standard QGIS02CadGis Fallback
DWG (R2000 and earlier)libopencad (CAD)Usually present
DWG (R2004+)libopencad (CAD)Usually fails on modern DWGODA File Converter → DXF → GDAL DXF driver. LibreDWG dwg2dxf as tertiary fallback.
DGN v8DGNv8Not included (requires ODA Teigha)Pure-Python DgnV8Reader: OLE2 → zlib decompress → element parse
Personal GDB (.mdb)PGeoSometimes absentMsAccessDbReader: pyodbc → ODBC → spatial table scan
NCZ/NCANoneNo GDAL driver existsNCZ Engine v2: pure-Python block-oriented binary decoder

The fallback chain for each format is exercised automatically. The DGN v8 reader probes the OLE2 signature and falls back silently; the MS Access reader checks pyodbc availability and installed ODBC driver names; the ODA File Converter is location-discovered through a 7-step search. Users see only a clear error message when all tiers fail, with guidance on installing the missing component.

Spatial Data Quality and Validation

CAD-to-GIS conversion introduces several classes of potential data quality degradation. The plugin implements validation checks and corrective measures at each stage of the pipeline to minimise information loss.

Geometry Validity

QGIS memory providers and the GeoPackage driver enforce OGC Simple Features geometry validity rules. Invalid geometries (self-intersecting polygons, non-closed rings, zero-length segments) are rejected by the data provider. The plugin applies pre-write geometry repair through the coercion engine: curve segmentization eliminates curved geometries that are not supported by Simple Features; Z-coordinate dropping eliminates 3D geometries incompatible with 2D-only layers; single-to-multi conversion ensures type compatibility. The add_features_or_raise helper (in core/qgis_compat.py) wraps dataProvider().addFeatures() with a verification step: it compares the feature count before and after the add, and if fewer features were accepted than submitted, it attempts a second pass with geometry coercion (drop Z, segmentize curves, convert multi/single type) before raising a descriptive error.

Coordinate Range Validation

All decoded coordinates are validated against realistic bounds. The NCZ engine's Cursor class enforces \([-10^8, 10^8]\) for all coordinate values; values outside this range are rejected. The DGN v8 reader additionally validates that coordinates fall within [100,000, 16,000,000] and that the absolute difference between x and y coordinates is at least 1.0 — filtering out degenerate point clouds. The CRS detector's northing band check (3,800,000–4,800,000 m) catches coordinates that are in the correct numeric range but outside Turkey's geographic extent, flagging them as medium-confidence detections.

Feature Count Verification

Every stage that constructs QGIS layers tracks the number of features submitted vs. accepted. The conversion pipeline reports a summary: total entities in source, entities decoded (for NCZ selective decode), entities written to output, and entities skipped (with reasons). The NCZ v2 engine tracks unsupported geometry types in catalog.unsupported (a dict of {type: count}) and reports them in the parse result. Empty geometries and degenerate features (zero-length lines, zero-area polygons) are filtered with logged warnings, never as fatal errors.

Attribute Null Handling

CAD files frequently have attributes that exist on some entities but not others. The plugin preserves this faithfully: missing attributes become NULL in the GeoPackage output. The mojibake repair and PlanGML schema population operate only on non-null string values. The PlanGML empty-code policy deliberately leaves cells blank rather than filling them with invented values, maintaining a clean distinction between "this tabaka is in the catalog" and "this tabaka was unrecognised."

CRS Validation

After conversion, the output GeoPackage's CRS is verified to be valid and appropriate. The _effective_source_crs method applies a precedence chain: layer CRS (if valid and not EPSG:4326 when coordinates are clearly metric), explicit user-provided source CRS, coordinate-based auto-detection, target CRS, project CRS, and finally a safe default (EPSG:5253 for metric coordinates, EPSG:4326 for geographic). At each level, the CRS is validated before use; an invalid CRS at any level causes fallthrough to the next. This chain ensures that a CRS is always available, even when every signal fails, without silently applying a wrong one.

Memory Management for Large Datasets

Large CAD drawings and geodatabases present memory pressure challenges. The plugin uses several strategies to keep memory usage bounded:

Concurrency and Thread Safety

QGIS plugins run in the main thread, and all GUI operations must be dispatched on the Qt event loop. The conversion engines are single-threaded and not designed for concurrent use. However, the cache modules (cache.py, ogr_catalog_cache.py) are designed for multi-process safety: writes use atomic rename (os.replace of a tempfile), which is guaranteed atomic on POSIX and NTFS. Multiple QGIS instances reading the same cache files will not corrupt each other, though they may experience a stale read if one instance updates a cache entry while another reads it — a harmless condition that self-corrects on the next access when the fingerprint mismatch triggers a rescan.

DGN v8: OLE2 Compound Document Structure

The pure-Python DGN v8 reader operates on the OLE2 (Object Linking and Embedding) Compound Document format that MicroStation uses as its file container. Understanding this container is essential for diagnosing read failures.

An OLE2 file is a FAT (File Allocation Table) file system within a file. It contains: (a) a header (512 bytes) with magic number D0 CF 11 E0, sector size, and FAT sector count; (b) a directory (structured storage) enumerating named streams (equivalent to files); (c) a FAT chain linking data sectors; and (d) stream data in 512-byte or 4096-byte sectors. The DGN reader opens the OLE2 container, locates the design file stream, and passes its decompressed contents to the element parser.

Element data in DGN v8 is stored as a sequence of variable-length records. Each element begins with a 2-byte type field (line = 3, linestring = 4, shape = 6, text = 7/17) followed by a 2-byte level number, attributes (colour, weight, style), and coordinate data. Polygons are distinguished from polylines by element type: shape elements (type 6) whose vertex ring is closed (first and last points coincident within 10−6 map units). Complex elements (shared cells, text nodes, dimension elements) are represented as placeholder points with level/colour/style attributes preserved.

The reader handles two DGN v8 sub-formats: standard binary encoding and compressed (zlib) encoding. The olefile library (BSD-licensed, vendored) handles OLE2 parsing; zlib decompression is done via Python's built-in zlib module. Elements containing Unicode strings use the standard MicroStation UCS-2 or UTF-16 encoding in the element attributes.

KMZ Multi-Document Extraction Theory

The KMZ format is a ZIP archive (using DEFLATE compression) with a .kmz extension containing one or more KML documents and their referenced resources (images, 3D models, icons). The OGC KML 2.3 standard specifies that the root document must be named doc.kml, but does not restrict additional KML documents [OGC 2015]. Google Earth, the reference implementation, reads only doc.kml; any other KML files in the archive are ignored unless explicitly linked from the root document.

02CadGis departs from this convention to support multi-document KMZ files commonly produced by municipal GIS exports, where each thematic layer is stored as a separate KML document. The extraction algorithm:

  1. Extracts the entire KMZ to a temporary directory via zipfile.ZipFile.extractall().
  2. Enumerates all .kml files (case-insensitive) in the extraction tree.
  3. Prefers doc.kml as the primary document; if absent, chooses the first KML in sorted order.
  4. Returns the primary document path for immediate GDAL reading; the remaining documents are accessed by _kml_docs(), which walks the extraction directory and orders documents with the primary first.
  5. In _ogr_sources(), each KML document becomes an OGR source with a prefix derived from its stem ("boundaries.kml" → prefix "boundaries_"). When only one document exists, the prefix is empty for backward compatibility.

This approach ensures that no KML data inside a KMZ is silently dropped. The multi-document prefix keeps layer names distinct when two documents define a layer with the same name. GroundOverlay images referenced by relative paths in any KML document are resolved against that document's location in the extraction tree.

DWG Conversion: ODA File Converter Discovery Algorithm

The search for ODAFileConverter.exe is exhaustive and ordered by decreasing likelihood, ensuring that the most common installation paths are checked first while still covering edge cases:

  1. QSettings (plugin custom path). The value of zero2cadgis/oda_converter_path is checked first; this is set when the user manually locates the executable through the interactive setup dialog.
  2. QgsSettings (QGIS native settings). Three keys are probed: /qgis/odaFileConverterPath (QGIS general setting), /dwg/odaConverterPath (DWG-specific setting), and /Processing/Configuration/ODA_FILE_CONVERTER_PATH (Processing framework setting). These capture installations configured through QGIS's own DWG import workflow.
  3. Environment variables. ODA_FILE_CONVERTER_PATH, ODA_PATH, and ODA_CONVERTER are checked. These allow CI environments and containerised QGIS instances to point to the converter without interactive setup.
  4. System PATH. shutil.which("ODAFileConverter.exe") checks the executable search path. This covers installations that added the ODA directory to PATH during setup.
  5. Static install paths. Five known installation directories under C:\Program Files and C:\Program Files (x86) are probed: ODA\ODAFileConverter\, ODAFileConverter\, and C:\ODA\ODAFileConverter\.
  6. Glob search. A shallow glob in Program Files directories for ODAFileConverter* directories captures versioned installations (e.g. ODAFileConverter 25.6.0).
  7. Windows Registry. Both HKLM and HKCU are searched under SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall (and WOW6432Node for 32-bit on 64-bit) for entries whose DisplayName contains "oda". Matching entries' InstallLocation values are checked for the executable. Direct registry keys SOFTWARE\OpenDesign and SOFTWARE\ODA are also probed.

The ODA File Converter invocation uses a safe ASCII filename (input_converted.dwg) to avoid Unicode/Turkish filename issues with the CLI tool. The target DXF version is attempted in descending order (ACAD2018 → ACAD2013 → ACAD2010 → ACAD2000) to maximise compatibility with GDAL's DXF reader. Each version is tried independently; the first successful conversion that produces a non-empty DXF file is used.

Format History and Provenance

FormatIntroducedStandardising BodyCurrent VersionStatus
DXF (Drawing Exchange Format)1982Autodesk (de facto)R2024 (proprietary)Active; widely supported
DWG1982Autodesk (proprietary)R2024Active; requires external converter for modern versions
DGN v82000Bentley Systemsv8i / CONNECTActive; GDAL driver requires ODA Teigha
NCZ/NCA~1990sNetcad (proprietary)Varies by producer versionActive in Turkey; no public specification
KML2004 (Keyhole)OGC (since 2008)2.3 (OGC 12-007r2)Active OGC standard
KMZ2004 (Keyhole)OGC (KML 2.2 Annex)ZIP container for KMLActive; de facto standard
GeoJSON2008IETF (RFC 7946, 2016)RFC 7946Active IETF standard
GML2000OGC / ISO TC 2113.2.1 (ISO 19136:2007)Active ISO/OGC standard
GeoPackage2014OGC1.4.0 (OGC 12-128r19)Active OGC standard
File Geodatabase2006Esri (proprietary)ArcGIS 10.x / ProActive; GDAL OpenFileGDB driver reads v9/v10
Shapefile~1994Esri (de facto, 1998 whitepaper)Stable since 1998Legacy; superseded by GeoPackage
SpatiaLite2008Alessandro Furieri5.xActive; OGC adopted SpatiaLite GeoPackage extension

Format Reference

Complete Format Matrix

FormatExtensionEngineLayer SplitLiveExport
AutoCAD DXF.dxfCAD
AutoCAD DWG.dwgCAD
MicroStation DGN v8.dgnCAD
Netcad NCZ.nczNCZ
Netcad NCA.ncaNCZ
KML.kmlGIS
KMZ.kmzGIS
GML.gmlGIS
GeoJSON.geojsonGIS
CSV / TSV / TXT.csv, .tsv, .txtGIS
SpatiaLite / SQLite.sqlite, .dbGIS
GPX.gpxGIS
File Geodatabase.gdbGIS
Personal Geodatabase.mdbGIS

Format-Specific Notes

OGR Format Driver Reference

The following table lists the GDAL/OGR drivers used for each format, their availability in standard OSGeo4W QGIS builds, and any known limitations.

FormatOGR DriverRead SupportWrite SupportCRS AwarenessKnown Limitations
DXFDXFFullPartial (via QgsVectorFileWriter)NoCurved entities segmentized; HATCH entities read as outlines; MTEXT not fully parsed
DWG (R2000)CAD (libopencad)FullNoNoR2004+ files return 0 features; ODA File Converter needed
DGN v7DGNFullNoOptional (header)v8 files fail; DGNv8 driver needed for modern files
DGN v8DGNv8Full (if available)NoOptionalRequires ODA Teigha libraries; not in standard QGIS GDAL builds
KMLKML (LIBKML)FullFullEPSG:4326 onlyLarge files (>100 MB) may exceed DOM memory limits
KMZLIBKML (via ZIP extraction)doc.kml onlyYes (via QgsVectorFileWriter)EPSG:4326 onlyGDAL reads only doc.kml; 02CadGis reads all KML documents
GMLGMLFullFullFullNamespace-sensitive; malformed schemas or inaccessible schemaLocation URLs may fail
GeoJSONGeoJSONFullFullEPSG:4326 only (RFC 7946)Non-WGS84 CRS is a convention extension, not guaranteed interoperable
CSV/TSV/TXTCSV (delimitedtext in QGIS)FullFullUser-specified or auto-detectedSniffer reads first 256 KB; geometry columns beyond this must be manually selected
SpatiaLiteSQLiteFullFull (GPKG for output)FullReads SpatiaLite metadata; output always GeoPackage, not SpatiaLite
GPXGPXFullNoEPSG:4326 onlyTrack segments, waypoints, and routes read as separate layers
File GeodatabaseOpenFileGDBFull (v9/v10)NoFullPre-v9 GDBs fail; Esri proprietary extensions unsupported; directory-based
Personal GeodatabasePGeoFull (if ODBC available)NoFullRequires 64-bit MS Access Database Engine; .accdb support varies by ODBC driver version
NCZ/NCANone (proprietary)N/AN/APartial (SRS id + projection text)No GDAL driver exists; 02CadGis NCZ Engine v2 is the only open-source reader

Detailed Format Comparison: Geometry Support

Geometry TypeDXF/DWGDGN v8NCZ/NCAKML/KMZGeoJSONGMLGPKG Output
PointPOINT, TEXT, MTEXT, INSERTType 2 (point), 7 (text), 17 (text node)Type 1 (point), 5 (text), 6 (symbol), 13 (block ref)Point PlacemarkPointgml:PointPoint / MultiPoint
LineStringLINE, POLYLINE, LWPOLYLINEType 3 (line), 4 (linestring)Type 2 (line), 7 (polyline), 9 (compressed curve)LineString PlacemarkLineStringgml:LineString, gml:CurveLineString / MultiLineString
PolygonLWPOLYLINE (closed), HATCH, 3DFACEType 6 (shape, closed)Type 7 (closed polyline), 10 (box), 11 (map sheet), 12 (triangle), 15 (smart object)Polygon PlacemarkPolygongml:Polygon, gml:SurfacePolygon / MultiPolygon
Circle/ArcCIRCLE, ARCType 12 (arc), 14 (ellipse)Type 3 (circle), 4 (arc)N/A (must be segmentized)N/Agml:Circle, gml:ArcSegmentized to LineString
Spline/CurveSPLINEType 24 (B-spline), 25 (curve)Type 9 (compressed curve)N/AN/Agml:BSpline, gml:BezierSegmentized to LineString
Text/LabelTEXT, MTEXT, ATTDEFType 7 (text), 17 (text node)Type 5 (text)Placemark name/descriptionfeature.propertiesgml:featureMember attributesPoint + label column
Block/Cell/InsertINSERTType 34 (shared cell), 35 (shared cell def)Type 13 (block ref), 15 (smart object)N/AN/AN/ADecomposed or placeholder Point

Format Size Characteristics

The following table provides guidance on expected file sizes and practical limits for each format, based on real-world municipal and planning datasets.

FormatTypical Size RangePractical Upper LimitEncoding EfficiencyNotes
DXF (ASCII)100 KB – 500 MB~1 GB (GDAL memory)Low (text-based, verbose)ASCII DXF is 5–10× larger than binary equivalent. Binary DXF is rare.
DWG100 KB – 200 MB~500 MB (then ODA conversion)High (binary, compressed)DWG is compact; ODA DXF intermediate may be larger.
DGN v850 KB – 100 MB~200 MB (pure-Python reader memory)Medium (binary with optional zlib compression)Compressed DGN files are smaller. Element count, not byte size, determines read time.
NCZ/NCA50 KB – 20 MB~50 MB (municipal drawings)High (binary, compact records)Typical municipal drawing: 1–5 MB, 5,000–15,000 entities.
KML1 KB – 200 MB~64 MB (GroundOverlay scan limit)Low (XML, verbose)KML over 64 MB skips GroundOverlay scan for safety.
KMZ5 KB – 500 MB~1 GB (ZIP extraction)Medium (ZIP compressed KML)KMZ compression typically 5–10×. Temp extraction needs disk space.
GeoJSON1 KB – 500 MB~1 GB (GDAL memory)Low (text-based)GeoJSON is the least compact vector format. Use GeoPackage for large datasets.
GML10 KB – 1 GB~2 GB (DOM memory)Very low (XML, extremely verbose)GML can be 10–50× larger than equivalent GeoPackage. Schema validation adds overhead.
GeoPackage1 KB – 10 GB~140 TB (SQLite maximum)High (binary, SQLite storage)Recommended output format. Efficient storage, spatial index, portable.
File Geodatabase1 MB – 100 GB~1 TB (directory-based)High (binary, Esri-proprietary)Live mode avoids materialising. Conversion copies all features.
CSV/TSV1 KB – 1 GB~2 GB (GDAL text scan)Very low (text-based, no compression)Sniffer reads only first 256 KB. For files >100 MB, use database import instead.

Interoperability Notes


Appendix A — CRS Quick Reference

Drawing SaysEastingEPSGLabel
ITRF / 3 / Zone 396 digits5257TUREF / TM39
ITRF / 3 / Zone 398 digits5273TUREF / 3° GK zone 13
ED50 / 3 / Zone 336 digits2321ED50 / TM33
ED50 / 3 / Zone 338 digits2208ED50 / 3° GK zone 11
WGS 84 / UTM zone 36N6 digits32636WGS 84 / UTM 36N
Geographic (lat/lon)≤3 digits4326WGS 84
(empty / unrecognised)User must select manually

Complete EPSG code tables for all 28 Turkish projected CRS variants are maintained in core/crs_detect.py. The detector covers TUREF TM (5253–5259), TUREF GK (5269–5275), ED50 TM (2319–2325), ED50 GK (2206–2212), WGS 84 UTM (32635–32638), and ED50 UTM (23035–23038).

Appendix B — PlanGML Symbology Excerpt

Upper GroupExample TabakaFillStroke
KONUT ALANLARIPL_KONUT (Yerleşik)#FDE49B#B37400, 0.7 mm
KONUT ALANLARIPL_GELISME_KONUT#FEF0D9#D4A017, 0.7 mm
TICARET ALANLARIPL_TICARET#D47879#8B0000, 0.5 mm
EGITIM TESISLERIPL_ILKOKUL#FEFA96#B3A000, 0.5 mm
SAGLIK TESISLERIPL_HASTANE#FAC8C8#CC0000, 0.5 mm
ACIK VE YESIL ALANLARPL_PARK#BEE6B0#2E7D32, 0.3 mm
YOL VE ULAŞIMPL_YOL#FFFFFF#333333, 0.3 mm
PLANLAMA SINIRLARIPL_SINIR#FF0000, 1.2 mm dash

Complete catalog: 350+ rules in core/symbology.py. Sourced from the official e-Plan SLD files.

Appendix C — Glossary

TermDefinition
ACIAutoCAD Color Index — 255 indexed colours in DXF/DWG. Mapped to RGB for QGIS rendering.
CAD layer / LevelNamed grouping of entities within a CAD drawing. DXF: Layer; DGN: Level. The plugin splits by this grouping.
Collinear simplificationRemoving intermediate vertices lying on a straight line between neighbours. Reduces vertex count without visual change.
e-PlanThe Turkish Ministry's electronic plan portal (eplan.csb.gov.tr). Source of official gösterim standards.
GösterimTurkish: the official visual representation (colour, hatch, line type) of a plan function per Ministry standards.
Live modeZero-copy reference — data stays in the source file; QGIS reads on demand.
MojibakeGarbled text from incorrect encoding interpretation. Turkish CAD files frequently exhibit CP1254↔CP1252↔UTF-8 mojibake.
MPYYMekânsal Planlar Yapım Yönetmeliği — Turkish Spatial Planning Regulation. Defines the official UIP tabaka catalog.
NCZ / NCANetcad's native binary drawing formats. NCZ is standard; NCA is a compatible variant.
ODAOpen Design Alliance — provides ODAFileConverter for modern DWG conversion.
PASEPlanX Adaptive Symbology Engine — matches CAD tabaka to official e-Plan gösterim rules.
PlanGMLTurkish Ministry's XML-based spatial plan data standard. The plugin populates PlanGML schema columns.
SRS idNetcad-internal coordinate system identifier. Not an EPSG code — never use as one.
TabakaTurkish: layer. In planning, a named spatial feature category (e.g. PL_KONUT) per the MPYY.
TaramaTurkish: hatch pattern. Official tile image used as polygon fill for certain plan functions.
@TABNetcad's internal attribute table format inside NCZ files. Linked to geometry by name/label.

Appendix D — Bibliography & Third-Party Notices

CAD/GIS Conversion & Interoperability

Al-Sabban, W., Issa, R.R.A., & Olbina, S. (2022). The C2G Framework to Convert Infrastructure Data from Computer-Aided Design (CAD) to Geographic Information Systems (GIS). Informatics, 9(2), 42. DOI: 10.3390/informatics9020042

Zhu, J., Wright, G., Wang, J., & Wang, X. (2018). A Critical Review of the Integration of Geographic Information System and Building Information Modelling at the Data Level. ISPRS International Journal of Geo-Information, 7(2), 66. DOI: 10.3390/ijgi7020066

Liu, X., Wang, X., Wright, G., Cheng, J.C.P., Li, X., & Liu, R. (2017). A State-of-the-Art Review on the Integration of Building Information Modeling (BIM) and Geographic Information System (GIS). ISPRS International Journal of Geo-Information, 6(2), 53. DOI: 10.3390/ijgi6020053

Sani, M.J. & Abdul Rahman, A. (2018). GIS and BIM Integration at Data Level: A Review. International Archives of the Photogrammetry, Remote Sensing and Spatial Information Sciences, XLII-4/W9, 299–306. DOI: 10.5194/isprs-archives-XLII-4-W9-299-2018

Şenol, H.İ. & Gökgöz, T. (2024). Integration of Building Information Modeling (BIM) and Geographic Information System (GIS): A New Approach for IFC to CityJSON Conversion. Earth Science Informatics, 17, 3437–3454. DOI: 10.1007/s12145-024-01343-1

Line Simplification & Geometric Algorithms

Douglas, D.H. & Peucker, T.K. (1973). Algorithms for the Reduction of the Number of Points Required to Represent a Digitized Line or Its Caricature. Cartographica: The International Journal for Geographic Information and Geovisualization, 10(2), 112–122. DOI: 10.3138/FM57-6770-U75U-7727

Hershberger, J. & Snoeyink, J. (1992). Speeding Up the Douglas-Peucker Line-Simplification Algorithm. Proceedings of the 5th International Symposium on Spatial Data Handling, 134–143.

Coordinate Reference Systems & Geodesy

Knudsen, T. & Evers, K. (2017). Transformation Pipelines for PROJ.4. FIG Working Week 2017 Proceedings, Helsinki, Finland. URL: fig.net

Evers, K. & Knudsen, T. (2017). Transformation Pipelines for PROJ.4. Geophysical Research Abstracts, 19, EGU2017-8050. URL: copernicus.org

PROJ Contributors. (2024). PROJ — Coordinate Transformation Software Library. Open Source Geospatial Foundation. proj.org

ISO/TC 211. (2020). ISO 19136-1:2020 — Geographic Information — Geography Markup Language (GML) — Part 1: Fundamentals. International Organization for Standardization.

Geospatial Data Standards & Formats

OGC. (2015). OGC KML 2.3. OGC Standard 12-007r2. URL: docs.ogc.org

Butler, H., Daly, M., Doyle, A., Gillies, S., Hagen, S., & Schaub, T. (2016). The GeoJSON Format. RFC 7946, Internet Engineering Task Force. DOI: 10.17487/RFC7946

Yutzler, J. & Daisey, P. (Eds.). (2024). OGC GeoPackage Encoding Standard, Version 1.4.0. OGC Standard 12-128r19. URL: geopackage.org

OGC. (2006). OpenGIS Symbology Encoding Implementation Specification, Version 1.1.0. OGC Standard 05-077r4. URL: docs.ogc.org

Software & Tools

GDAL/OGR Contributors. (2024). GDAL — Geospatial Data Abstraction Library. OSGeo. gdal.org

Open Design Alliance. (2024). ODA File Converter. opendesign.com

Turkish Planning Regulation & Standards

T.C. Çevre, Şehircilik ve İklim Değişikliği Bakanlığı. (2024). Mekânsal Planlar Yapım Yönetmeliği (MPYY). Resmî Gazete.

T.C. Çevre, Şehircilik ve İklim Değişikliği Bakanlığı. (2024). e-Plan Gösterim Kataloğu. eplan.csb.gov.tr

Third-Party Notices. The PlanGML symbology reproduces the official Ministry e-Plan gösterim standards from publicly available sources. No official font files are redistributed. The MpyyUipDb_2026_02_27.gpkg catalog is compiled and maintained by Yusuf Eminoğlu from the Ministry's published tabaka lists. The vendored olefile library is used under its BSD license for DGN v8 OLE2 reading. Full attribution: THIRD_PARTY_NOTICES.md.

Appendix E — NCZ Block Type Reference

The following table documents the known NCZ block types understood by Engine v2. Types not listed here are container blocks (kinds {0, 5, 14, 48, 108, 111, 132, 150, 180}) that may embed geometry records, or are unrecognised and skipped with a logged count.

KindNameDecoderKey Geometric Semantics
1Pointdecode_pointSingle coordinate pair (northing-first). Name string at G+86. Used for point features, survey markers, and CAD symbols.
2Linedecode_lineTwo-vertex segment: start at +8/+16, end at (size-19)/(size-11). Simplest CAD primitive.
3Circledecode_circleCentre point + diameter (from f64 difference at +50 and +66). Segmentized to polygon in output.
4Arcdecode_arcCentre + radius + start/end angles (radians). Used for curved road alignments and parcel boundaries.
5Textdecode_textInsertion point + text string + height + rotation. Label field candidate in output. Multiple fallback text locations.
6Symboldecode_symbolInsertion point + symbol code + size + rotation. Point marker from Netcad symbol library.
7Polyline / Polygondecode_polylineVariable-length vertex array (24 bytes per vertex: 3×f64). Closure detected by endpoint proximity. Rectangle metrics computed for oriented boxes.
9Compressed Curvedecode_compressed_curveOrigin + sequence of f32 delta pairs (18-byte records). Efficient storage for smooth curves; duplicates skipped by proximity check.
10Boxdecode_boxTwo opposite corners defining an oriented rectangle. Rotation in radians. Plan name token extracted for labelling.
11Map Sheetdecode_map_sheetFour-corner bounding box. Sheet name extracted as first printable length-prefixed string. Used for map grid frames.
12Triangledecode_triangleThree vertices with optional Z. Area validated (> 0.0001) to reject degenerate triangles. Used in TIN surfaces and 3D meshes.
13Block Referencedecode_block_referenceInsertion point + optional name + rotation. References a block definition stored elsewhere in the file.
15Smart Objectdecode_smart_objectComplex compound entity: width, height, rotation (grads), scale, grid coordinates, label. Represents parametric CAD objects. Rotation conversion: grads × 0.9 = degrees.

NCZ Coordinate Conventions

All coordinate pairs in NCZ geometry records are stored northing-first: the first f64 value at +8 is the northing (Y in GIS), and the second f64 value at +16 is the easting (X in GIS). The map_point(first, second) helper transposes these to GIS convention: {"x": second, "y": first, "z": z}. This transposition is verified bit-for-bit against v1 output. Z values are stored as f32 at offset +24; some record types store an alternative Z at +28 (used as fallback when +24 is 0.0). All coordinate values must be finite and within [−108, 108] to pass the range validation gate in finite_pair_in_range().

@TAB Attribute Table Variants

@TAB records are classified into three variants by the attribute decoder:

VariantDetection CriteriaKey FieldsUse Case
LabelPrintable length-prefixed label at offset 28/29, all bytes in ASCII printable rangelabel text, prefix f32, code u16, style code u32, 3 coordinate pairs (f64)Named entities with spatial reference: parcels, buildings, zones. Label links to geometry entity name.
SegmentRecord ≥ 119 bytes, f64 pairs at 17/25, 45/53, 87/95, 103/111 all look like projected coordinates (|v| in [103, 108])4 coordinate pairs, style code, 4 flag bytesLinear referencing: road segments, pipeline sections, cadastral edges.
ASCIIAnything else. All printable length-prefixed ASCII fields collectedascii_values (pipe-joined), table_ref_inlineTabular metadata: material schedules, quantity takeoffs, code lists.

Tables are grouped by their @TAB marker suffix (e.g. @TAB1, @TAB2) and presented as separate checkable rows in the dock's layer tree. Checking both a geometry layer and its matching @TAB table triggers an automatic attribute join on entity name (for label variants) or on spatial proximity (for segment variants, joining to the nearest polyline segment).

Producer-Specific Quirks in NCZ Files

Netcad's proprietary format exhibits several documented quirks that the engine handles transparently:

Benchmark Reproducibility

All performance claims in this manual are reproducible. The benchmark script (benchmarks/ncz_engine_benchmark.py) records fixture SHA-256, Python/QGIS build details, p50/p95 duration, MiB/s throughput, entities/s, peak Python allocation (via tracemalloc), and a normalised output SHA-256 digest. A benchmark run is invalid if repeated output hashes differ. To reproduce:

python zero2cadgis/benchmarks/ncz_engine_benchmark.py \
    C:/path/small.ncz C:/path/large.ncz \
    --label v1-baseline --output C:/path/v1-baseline.json

The benchmark JSON includes fixture metadata (SHA-256, byte size, producer, covered geometry types, expected entity/table counts) and is designed for before/after comparison during engine development. The synthetic fixture corpus (tests/ncz_fixtures.py) exercises every decoder path, both block layouts, embedded containers, metadata blocks, and @TAB tables, and is validated field-by-field against v1 output. Validation against real municipal drawings requires setting the ZERO2CADGIS_NCZ_FIXTURE environment variable to a licensed drawing path; this opt-in test was validated on a 1.2 MiB / 8,163-entity municipal Netcad file (60 layers, ITRF/3 zone 42).

Appendix F — Configuration Reference

SettingStorageDefaultDescription
zero2cadgis/oda_converter_pathQSettings(empty)Custom path to ODAFileConverter.exe. Set via the interactive setup dialog. Overrides all auto-detection.
zero2cadgis/last_source_dirQSettings(empty)Last-used directory for source file selection. Persisted between sessions.
zero2cadgis/last_target_dirQSettings(empty)Last-used directory for GeoPackage output. Persisted between sessions.
zero2cadgis/last_target_crsQSettings(project CRS)Last-used target CRS authid (e.g. EPSG:5257). Persisted between sessions.
zero2cadgis/cad_split_layersQSettingstrueDefault state of "Split into CAD layers" checkbox.
zero2cadgis/cad_simplifyQSettingstrueDefault state of collinear simplification checkbox.
zero2cadgis/plan_typeQSettingsAUTODefault PlanGML plan type: UIP, NIP, CDP, or AUTO.
ZERO2CADGIS_NCZ_CACHE_DISABLEEnvironment(unset)Set to 1/true/yes to disable the NCZ index cache. Useful for debugging or when working with rapidly-changing files.
ZERO2CADGIS_OGR_CACHE_DISABLEEnvironment(unset)Set to 1/true/yes to disable the OGR catalog cache.
ZERO2CADGIS_NCZ_FIXTUREEnvironment(unset)Path to a real NCZ file for opt-in validation testing. Used by test_ncz_engine_v2.py to assert bit-exact parity for a specific drawing.
ODA_FILE_CONVERTER_PATHEnvironment(unset)Path to ODAFileConverter.exe. Checked during ODA discovery (tier 3). Useful for CI and containerised environments.
ODA_PATHEnvironment(unset)Alternative environment variable for ODA installation directory.
ODA_CONVERTEREnvironment(unset)Alternative environment variable for ODA converter executable path.