02CadGis

Universal CAD/GIS Importer — Academic Reference Manual
v4.1.2 · Yusuf Eminoğlu · GEOPHILO · October 2026 · GitHub · GitLab

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 MPYY transfer writes an imar plan's tabaka into MPYY 1.1.7 feature types and draws them with the Ministry's UIP / NIP / CDP styles. 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, MPYY transfer), and CAD & GIS Exporter (DXF/KML/KMZ/MBTiles 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+):

02CadGis carries that gösterim as the MPYY style bundle under mpyy/ — the Ministry's e-Plan SLDs rewritten to the MPYY 1.1.7 schema, together with the tarama tiles and the plan symbol fonts they reference. The bundle travels inside the plugin: nothing is downloaded and no style server is needed. Resolving a drawing's tabaka onto it is deliberately conservative, because a wrong function is worse than an unresolved one. Each layer name is resolved by an exact match, by a mapping the user confirmed earlier and the plugin remembered, or by a spelling rule that cannot change the meaning (a copy number, an export suffix, the _ALANI ending, a PL_ prefix). Anything else is only proposed — ranked word by word against the Ek-1e function names and MPYY codes — and waits for confirmation. A tabaka that resolves to 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. It is the only decoder in the tree: the earlier implementation has been removed, and core/netcad_parser.py is now a thin first-party facade that re-exports the v2 result model and readers. Its correctness is guarded by a synthetic fixture corpus that exercises the decoder paths and both block layouts, and by an opt-in parity test against a real 8,163-entity municipal drawing.

ModuleFileRole
Binary Readerbinary.pyBounds-checked cursor primitives. Every read validates offset and length — no buffer overrun possible.
Block Scannerblocks.pyWalks the block chain and builds the drawing's metadata: layers, the LEX.ST2 style table (colours and pen widths), and the CRS hints.
Geometry Decodergeometry.pyRegistry of decoders keyed by entity kind (point, line, polyline, circle, arc, text, block reference, …), with the KIND_* vocabulary and each kind's geometry family.
Smart Object Propertiesproperties.pyParses the Netcad 8 Smart Object property bag — the source of the zoning values the plan notation and the MPYY transfer read.
Attribute Decoderattributes.pyDecodes @TAB attribute tables stored inside drawings.
Index Cachecache.pyFingerprinted on-disk cache of the catalog, keyed by file size and modification time and stamped with a cache version.
Parserparser.pyOrchestrator: the two-phase index / selective-decode flow, and parse_file. Reports its backend as a constant.

The result model itself (NetcadEntity, NetcadAttributeTable, NetcadParseResult) lives one level up in core/ncz_engine/model.py, shared by the engine and everything that consumes it.

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–32638—35N–38N
ED50 / UTM23035–23038—35N–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 each file's layers stay separate, under their own file-name prefix. Build unified upper layers merges the tabaka into one layer per geometry family, across files if you are importing more than one. @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 or label. Optional geometry metrics add length, area and centroid fields.

MPYY Transfer (Turkish İmar Plans)

TR-Only MPYY Style Overview

TR-Only MPYY Style is an opt-in mode that turns a Turkish implementation, master or environmental plan from a raw CAD drawing into an MPYY workspace: a GeoPackage whose layers are the MPYY 1.1.7 feature types, written with the plan's code values and drawn with the Ministry's own styles.

It is offered in two places, and it is off by default in both:

PanelControlApplies to
Netcad NCZ/NCA importerTR-Only MPYY Style: MPYY structure and styles (UİP / NİP / ÇDP)Every checked drawing
CAD & GIS converterTR-Only MPYY Style (DXF / DWG): MPYY structure and stylesDXF and DWG sources only; checking it for another format raises a warning and is ignored
Leave it off for anything that is not an imar plan. Topographic surveys, utility networks, cadastral sheets and civil-engineering drawings have no MPYY function, and forcing them through the transfer would replace their tabaka names and their drawing colours with a classification that does not describe them. With the mode off, every import behaves exactly as the rest of this manual describes.

Switching the mode on also changes two neighbouring controls, because the transfer owns the layer structure: Build unified upper layers is disabled and unchecked while the mode is active, and Apply original ARGB colors is locked on. The ARGB lock is not cosmetic — the layers that cannot be transferred are handed back in the drawing's own colours, and those colours have to survive (see Unmatched Layers).

MPYY Styles & Reference Scale

The styling in this mode is MPYY Studio's MPYY UİP / NİP / ÇDP style set, carried inside 02CadGis under mpyy/. Each level is one Ministry e-Plan SLD per MPYY feature type, with the Ek-1e catalogue corrections and the plan symbol fonts those styles reference. Nothing is downloaded at run time and no style server is involved; the retired e-Plan database (symbology-style.db) is not read by any code path. Appendix B lists what the bundle contains.

Plan level. The Plan level selector offers Auto, Implementation plan – UİP (1/1000), Master plan – NİP (1/5000) and Environmental plan – ÇDP (1/25,000+). Auto reads the level from the file name: the marker words UIP/UYGULAMA/MUIP, NIP/NAZIM/MNIP and CDP/CEVRE/MCDP first, then a scale number (500, 1000, 2000 → UİP; 5000, 10000 → NİP; 25000 and above → ÇDP). The name is matched with Turkish letters folded, so ÇDP and CDP both read as an environmental plan. If a file name says nothing at all, Auto assumes UİP; if the level still cannot be named, the import stops and says so rather than writing the plan into the wrong style set.

Reference scale. UİP, NİP and ÇDP are drawn at 1/1000, 1/5000 and 1/25,000, and the styles scale with the view, so the on-screen plan looks like the printed sheet at that scale. Area pictograms are placed at the regulation's 10, 7 and 5 mm, and the legend is scoped to the plan in front of you: it lists only the values the drawing actually uses, not the whole catalogue.

The catalogue. The official tabaka identity — upper group, MPYY function and code, and the geometry the function is defined for — comes from a catalogue generated from the Mekânsal Planlar Yapım Yönetmeliği UİP database. A tabaka the catalogue does not know is given empty code cells rather than an invented code, and is placed in DİĞER PLAN ALANLARI — deliberately the only group name in the output that is not the Ministry's.

Layer-Name Resolution & Confirmation

Everything hinges on answering one question per CAD layer: which MPYY function is PL_KONUT? The transfer answers it in four ways, and only the first three can write an MPYY code without a person looking at it:

  1. Exact. The layer name is a key of the tabaka crosswalk table. Nothing is inferred.
  2. Confirmed before. The name was ticked in the confirmation table on an earlier drawing and is remembered (see below).
  3. Spelling rule. The name differs from a crosswalk key only in ways that cannot change its meaning: a trailing copy number (_2), a Netcad export suffix (_NETCAD, _NETC, _NTC, _NET), the _ALANI / _ALAN / _TESISI / _TESIS / _TES ending, the PL_ prefix, or a compact versus underscored spelling. A rule is applied only when every rule that fires points at the same key; if two readings are possible, nothing is applied and the layer goes to the confirmation table instead.
  4. Proposal. Anything else is only proposed. A proposal never becomes an MPYY code on its own, however confident the ranking is.

Proposals are ranked word by word against the Ek-1e function names and MPYY codes: a synonym list, a stop-word list, common layer prefixes, Turkish plural and possessive endings, run-together names split back into words, and an inverse-document-frequency weight so that a rare word counts for more than a common one. Geometry is used as a filter — a line tabaka is not proposed against a polygon function. If a single word fits more than eight different functions it is treated as uninformative and yields no proposal at all. Layer names containing IPTAL or ITIRAZ (cancelled, objected) are never resolved and never proposed.

The confirmation table. When anything is left unresolved, the import opens TR-Only MPYY Style {UİP/NİP/ÇDP} — match CAD layers. Its columns are Confirm, CAD layer, Geometry, Features, MPYY function (type to search) and Reason, and the reason column states which rule or ranking produced the row. The rows start unticked: a proposal is something you accept, not something you have to remember to reject, so that a drawing full of unrecognised tabaka cannot be transferred wholesale by clicking through. You can tick a proposal, or ignore the ranking entirely and type to search for any MPYY function by hand — doing so ticks the row for you. Rows with no proposal at all are hidden behind Also show the N layer(s) without a proposal. The dialog then offers Confirm ticked and transfer or Transfer without confirming, and the second is a deliberate, informed choice rather than the default.

Remembered mappings. A mapping you confirm is written to a per-user file, <QGIS profile>/mpyy/tabaka_eslesmeleri.json, keyed by plan level. The same tabaka name then resolves by itself on the next drawing, so a municipal spelling you had to confirm once is only ever confirmed once. The file is written atomically through a rename, so an interrupted write cannot leave a half-file behind, and it is shared with the other plugins that carry the same module. MPYY_TABAKA_ESLESME points the file somewhere else — see Appendix F.

Plan Notation & Carried Zoning Values

An imar plan carries its zoning decisions in text: nizam, kat, TAKS, KAKS / emsal, Hmax, front and side setbacks. The transfer reads them from two places — the notation texts in the drawing and the property bags of Netcad 8 Smart Objects — and writes them into the MPYY fields, but only where the MPYY form accepts the value. A value no MPYY field can hold is dropped, not coerced into the nearest field. Where the drawing states a value more than once, it is kept only if every statement agrees; a contradiction is not resolved by picking one.

Plan notation. Rather than let the MPYY area layers label themselves, the transfer redraws the planner's own notation where the planner placed it. Every Smart Object whose properties carry a building-rights or road-width parameter becomes a point in a <file>_PLAN_NOTATION group, split into two layers:

LayerCarries
Building notationYapı düzeni (nizam), kat adedi, TAKS and its type, emsal / KAKS and its type, yapı yüksekliği and its type, ön and yan bahçe mesafeleri, and the symbol position — drawn as the Ek-1e building notation (the nizam / kat circle, the TAKS / KAKS circle, E =, Yençok).
Road widthsThe road width from the Smart Object, drawn as the width in a circle.

Empty layers are not created. To keep the plan from being drawn twice, the same transfer hides the Smart Object frames in the leftover drawing layers with a layer subset, and switches the building-notation labels of the MPYY area layers off. The plan areas keep their values as attributes either way — only the duplicate labelling is suppressed.

Unmatched Layers, Unfit Features & Pen Widths

Not every layer belongs in the MPYY workspace, and the transfer says so rather than absorbing it. Two things are kept out:

Both are handed back as one layer-tree group named <file>_UNMATCHED_LAYERS, drawn in the drawing's own ARGB colours — which is why that control is locked on in this mode. The import summary states how many layers and features went there, so the split is never silent. Nothing is discarded and nothing is guessed: what the MPYY workspace could not describe is still in front of you, in the colours it was drawn in, ready to be classified by hand.

Pen widths. Netcad stores a pen width in millimetres per layer, in the drawing's own style table, and 02CadGis carries it through: every feature gets a line_width_mm attribute, lines are drawn at that width and polygon outlines at that width as well. A layer that sets no pen falls back to 0.25 mm — chosen because a heavier default turned every contour and helper line of a plan bold. In the MPYY transfer the same value fills the MPYY CizgiKalinligi field, so a feature that keeps its drawing pen in QGIS keeps it in the MPYY output, and önerilen / korunan / düzeltilen cephe lines take their width from it.

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
Destination CRS:CRS(project CRS)CRS written to the output layers. Netcad drawings store an SRS id rather than an EPSG code, so the panel preselects one from the drawing's projection text and a sample of its coordinates; the selection is only a preselection and your choice is what gets used.
Simplify collinear verticesbooleanTrueDrop vertices that lie on the straight line between their neighbours, within tolerance. See Collinear Simplification.
Clean duplicate nodesbooleanTrueRemove repeated consecutive nodes and near-zero segments left by the drawing.
Calculate geometry metadata (Area, Length)booleanTrueAdd the geometry metric columns — length, area and centroid — computed from each feature's geometry in target CRS units.
Polyline Closure Tolerancedouble, 0.0–10.0 m0.10 mVertex gap below which an open polyline is closed into a polygon. Keep it small unless the drawing has known snap gaps: it is the control that decides whether a cadastral parcel closes.
Apply original ARGB colors and line stylesbooleanTrueDraw each layer with the drawing's ARGB colour and its pen width, as a categorised renderer. NCZ colour codes: 0 = by layer, 1 = forced blue, 255 = forced red; layer colours and pen widths come from the drawing's style table. Locked on while TR-Only MPYY Style is active.
TR-Only MPYY Style: MPYY structure and styles (UİP / NİP / ÇDP)booleanFalseImport as an MPYY workspace instead of raw CAD layers. See MPYY Transfer. Off by default and intended to stay off for anything that is not an imar plan.
Plan level:enumAutoAuto (detect from file name), Implementation plan – UİP (1/1000), Master plan – NİP (1/5000) or Environmental plan – ÇDP (1/25,000+). Read only when TR-Only MPYY Style is on.
Convert text elements to map labelsbooleanTrueTurn drawing text into QGIS labels on the layer that owns the text. Point layers keep a subtle anchor marker so an insertion point stays visible.
Join attribute tables (@TAB) automaticallybooleanTrueLink @TAB tables back to geometry where a matching name or label field exists. With it off, tables are still decoded and can be joined by hand.
Attribute columns:column set(all)Untick a column to leave it out of the written layers. Columns the styles, the labels, the three-layer categories and the MPYY transfer read are locked on and cannot be dropped; unticked columns are discarded only after every step that needs them has run. MPYY layers always carry their own MPYY 1.1.7 columns regardless.
Build unified upper layers (Polygon / Line / Point)booleanTrueMerge the drawings' tabaka into one layer per geometry family instead of one layer per tabaka. Disabled and unchecked while TR-Only MPYY Style is on, because the transfer defines the layer structure itself.
Merge all layers into 3 layers (Polygon / Line / Point-Text)booleanFalseWrite every tabaka of a drawing into exactly three layers — _POLYGON, _LINE, _POINT/TEXT. Each feature keeps its tabaka in layer_name and the renderer is categorised by that field, so every tabaka keeps its own drawing colour; helper and pen tabaka are listed but switched off. With several drawings and unified upper layers on, they share the three layers.
Import directly as temporary scratch layers (no GPKG)booleanFalseWrite to QGIS memory layers instead of a GeoPackage. In MPYY mode the workspace goes to a temporary file instead.

Two engine behaviours are not switches. Selective decode always applies: choosing a drawing indexes only its layers and metadata, so the layer tree appears almost immediately even for large municipal files, and geometry is decoded only for the layers checked at import time. The index cache is likewise always on unless ZERO2CADGIS_NCZ_CACHE_DISABLE is set; it is keyed to the drawing's size and modification time and rebuilds itself when the drawing changes. Clear cache on the Netcad tab resets it by hand.

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.
Select Source Layer:enum(first layer)One vector layer from the project. For MBTiles the list gains a first entry, [All Visible Canvas Layers / Project], which renders the whole canvas rather than one layer.
Target Export Format:enumDXFAutoCAD DXF (*.dxf), Google Earth KML (*.kml), Google Earth KMZ (*.kmz) or Web Map Tiles MBTiles (*.mbtiles). DXF is written through QgsVectorFileWriter with attribute creation skipped, so the drawing carries geometry and layer structure but no attribute table. KMZ is a KML written as doc.kml inside a DEFLATE zip.
Output CRS:CRS(layer CRS)Enabled for DXF only, where the engineering or project CRS is meaningful. The control is disabled and forced for the other two formats, and the hint under it says which: KML/KMZ is always EPSG:4326 for standards-compliant Google Earth positioning, and MBTiles is always EPSG:3857 (Web Mercator) with TMS/XYZ tiling.
Feature Scope: Selected features onlybooleanFalseExport only the features currently selected on the source layer. Hidden for MBTiles, which renders the canvas. Selecting this with nothing selected on the layer is an error rather than an empty export.
Save Location:file path(user-selected)Destination file. The write goes to a temporary file that is validated and only then published over the destination, so an interrupted export cannot replace an existing deliverable with a partial file.

Tile Settings appear when MBTiles is chosen:

ParameterRangeDefaultDescription
Min Zoom:0–2414Lowest zoom level of the pyramid. Lower values add a wider overview and cost tiles fast.
Max Zoom:0–2416Highest zoom level. This is the one that decides whether a plan is legible when zoomed in.
Tile formatenumPNGPNG (Transparent) or JPEG (Opaque). PNG keeps transparency, which is what makes an overlay usable; JPEG is smaller. JPEG quality is 75.
DPI:72–60096Tile resolution. 96 is the standard web-map DPI and the right answer unless you have a reason.
Metatile:1–81Metatile buffer. 1 is fastest and lightest on memory.
Extent:enumAutoCAD / Vector Data Extent (Auto) renders only the drawing area — fast and compact — or Current Map Canvas Extent renders what is on screen.

An estimate label under these controls counts the tiles the current settings would produce and reports what to expect: Fast, < 5 sec up to about 250 tiles, Moderate, ~10–30 sec up to about 2,500, and a red warning above that. The exporter refuses to run above an estimated 25,000 tiles and says why, rather than filling a disk or freezing QGIS. The number of tiles actually written is read back from the output and reported with the feature count.

The Netcad tab carries a shortcut to this panel, Need raster tiles? Open MBTiles Exporter →, which opens the exporter format already set to MBTiles — the intended route for turning a converted plan into a web-map pyramid in one step.

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, or its current selection, to DXF, KML or KMZ through QgsVectorFileWriter. DXF is written with attribute creation skipped, so it carries geometry and layer names for CAD collaborators but no attribute table; KML and KMZ are forced to WGS 84 (EPSG:4326) so Google Earth positions them correctly. Each write goes to a temporary file that is validated first and only then published over the destination, so an interrupted export cannot destroy an existing deliverable.

MBTiles / Tile Pyramid Export

The same panel writes a raster tile pyramid — .mbtiles, in TMS or XYZ addressing — from the styled canvas, using QGIS's native tile algorithm. Source selection differs from the vector exports: the layer list gains [All Visible Canvas Layers / Project], which renders the whole canvas with its real styling rather than one layer's geometry. The output is always reprojected to EPSG:3857 (Web Mercator), which is what every web map expects, and tiles are antialiased.

The controls are Min and Max Zoom (default 14 and 16), tile format (PNG (Transparent) or JPEG (Opaque), quality 75), DPI (default 96, the standard web-map value), Metatile (default 1, the fastest and lightest on memory) and Extent — the drawing's own extent or the current canvas. An estimate label counts the tiles the current settings imply and says what to expect: under about 250 tiles it reports Fast, < 5 sec; up to about 2,500, Moderate, ~10–30 sec; above that it warns. The exporter refuses a run estimated above 25,000 tiles rather than filling a disk or freezing QGIS, and reports the number of tiles actually written, read back from the output.

Transparency is the reason to prefer PNG here: a plan exported as an opaque JPEG cannot be laid over a basemap. Use JPEG only when file size matters more than overlaying. The Netcad tab's Need raster tiles? Open MBTiles Exporter → link jumps straight to this panel with MBTiles selected, which is the intended route from a converted plan to a web-map deliverable.

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.

Batch Tools

Batch Spatial Extent Filter

Surveying and municipal archives arrive as a directory of hundreds of sheets — paftas — and the task is usually to find the handful that cover one area. Opening them one at a time in QGIS is what the filter exists to replace. It scans a folder (recursively by default) or an explicit file list and reports which drawings intersect a boundary without loading any of them into memory: only the header and the extent are read, so an unmatched sheet costs nothing but its file read.

The extensions it understands are the ones the plugin imports: .ncz .nca .dxf .dwg .dgn .kml .kmz .shp .gdb .geojson .json .gml .sqlite .db .gpx .accdb .mdb .csv .tsv. File geodatabases are treated as one unit each rather than as a folder of files. For NCZ and NCA the extent comes from the drawing's own decoded coordinates, with origin-artefact points and non-finite or oversized values discarded; for everything else it comes from the OGR layer extents and the source CRS.

Boundary sourceUses
Active Map Canvas ExtentWhatever the map canvas currently shows. The fastest way to say "here".
Selected Feature(s) in Polygon LayerA polygon layer in the project. Use only selected polygon features (on by default) unions the current selection instead of the whole layer — a district boundary, an administrative area, a site outline.
Print Layout Map ExtentThe extent of a print layout's map item. This is the one to use when the sheet boundary is the deliverable's frame rather than an arbitrary view.
Manual Bounding BoxA bounding box typed in directly, for an area you know the coordinates of.

The match is either Intersects or Within, with an optional metre buffer so that a sheet whose edge only touches the boundary can be included or excluded deliberately. The comparison uses real geometry and CRS transforms when QGIS can build them and falls back to a plain bounding-box test when it cannot, so the filter still works on a layer whose CRS is unassigned. Results are timed and reported as Scan complete in N s: M matched out of K candidate files.

Three things consume the result. Preview Footprints on Canvas draws the matched extents as a labelled overlay so you can see the coverage before committing. Import Matched Files then takes exactly the matches through the normal import path, in one of three output modes: Directly into QGIS Canvas (the default), Unified GeoPackage (all matches into one .gpkg), or Copy matched files to folder (the originals copied out, converted by nothing). Send to CAD Tab hands the selection back to the converter tab instead, so you can inspect it there first. This is the intended way to pull a district's worth of sheets out of a provincial archive without opening the ones you do not need.

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 name, geometry family and record count. 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 3a: Filtering the list. The box above the tree filters by name and by geometry. Every word you type must match: LINE, POLYGON, POINT or TEXT keep the layers holding that geometry, and any other word must appear in the layer name. So PL_ line lists the plan layers that contain lines. Turkish letters are matched loosely — ı/i/İ/I are the same letter and ş ç ğ ö ü match s c g o u, so askeri finds PL_ASKERI_ALAN and yapı finds SM_YAPILASMA. Select All / Deselect All act on the listed layers only, so a filter is a safe way to bulk-check a subset; hidden layers keep whatever state they had.

Step 3b: Attribute columns. Untick any column you do not want written. The columns the styles, the labels, the three-layer categories and the MPYY transfer read are locked on — dropping layer_name, the colour, the label or the text height would silently change what you see. Unticked columns are discarded only after every step that needs them has run, and MPYY layers keep their own MPYY 1.1.7 columns regardless.

Step 4: TR-Only MPYY Style (optional). For an imar plan, check TR-Only MPYY Style: MPYY structure and styles (UİP / NİP / ÇDP) and leave Plan level on Auto unless the file name does not say which plan it is. The import then writes an MPYY workspace instead of raw CAD layers, and any tabaka it cannot resolve comes back to you in the confirmation table rather than being guessed. See MPYY Transfer Workflow. Leave this off for topographic, cadastral, utility and engineering drawings.

Step 5: Batch options. Build unified upper layers merges the tabaka into one layer per geometry family; Merge all layers into 3 layers goes further and writes exactly three. Geometry metadata adds the length, area and centroid columns, useful for quality checking. Both are covered in MPYY Transfer Workflow; the merge controls are disabled while the MPYY mode is on, because the transfer defines the layer structure itself.

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.

MPYY Transfer Workflow

Step 1: Decide that this is an imar plan. The mode is for Uygulama, Nazım and Çevre Düzeni plans. If the drawing is a topographic survey, a utility network, a cadastral sheet or an engineering drawing, stop here and import it with the mode off — the rest of this section does not apply to it, and forcing it through would replace its tabaka names and drawing colours with a classification that does not describe it.

Step 2: Enable the mode and pick the level. On the Netcad tab, check TR-Only MPYY Style: MPYY structure and styles (UİP / NİP / ÇDP); on the converter tab, the equivalent box applies to DXF and DWG only. Leave Plan level on Auto in the normal case: a file named 1000_BAHCESARAY_IMAR.ncz resolves to UİP because of the 1000, 5000_… resolves to NİP and 25000_… to ÇDP, and a name containing NAZIM resolves to NİP whatever its scale prefix says. Set the level by hand when the file name is uninformative; if the level cannot be determined at all, the import stops and tells you rather than styling the plan as the wrong kind.

Step 3: Answer the confirmation table. Layers whose names match the crosswalk exactly, were confirmed on an earlier drawing, or differ only by a copy number, a Netcad export suffix, a PL_ prefix or an _ALANI-type ending transfer without asking. Everything else arrives in TR-Only MPYY Style {UİP/NİP/ÇDP} — match CAD layers, unticked, with the reason each was proposed. Tick what is right, type to pick a function by hand where the proposal is wrong, and leave the row unticked where you would rather keep the drawing's own layer. Confirmed rows are remembered for the next drawing, so this table shrinks as you work through an archive.

Step 4: Read the result. The import produces an MPYY workspace GeoPackage for the level, the layers styled at the plan's reference scale with a legend scoped to the values the plan uses, and — where the drawing carried the planner's own notation — a <file>_PLAN_NOTATION group with Building notation and Road widths. Anything the transfer could not place is in <file>_UNMATCHED_LAYERS, in the drawing's own colours. The summary confirms the split by name and by count. Check it before delivering: an unmatched layer is a decision still to be made, not an error.

Step 5: Layer structure. Two controls interact with this mode. With the mode off, Build unified upper layers merges the tabaka into one layer per geometry family, and Merge all layers into 3 layers (Polygon / Line / Point-Text) writes exactly three layers labelled <owner>_POLYGON, <owner>_LINE and <owner>_POINT/TEXT; each feature keeps its tabaka in layer_name, the renderer is categorised by that field so every tabaka keeps its own drawing colour, and helper and pen layers are listed but switched off. With the mode on, those two are superseded and the first is disabled outright — the MPYY workspace's layer structure is the MPYY feature types, and tabaka that have no MPYY type are what ends up in the unmatched group instead.

The single most common mistake with this mode is leaving it on. It is off by default for that reason. If an import that used to produce recognisable CAD layers suddenly produces MPYY feature types, an MPYY workspace with an empty code column, or a group of layers in the drawing's own colours, check this checkbox first.

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.
A tabaka that should be a known function comes back in the confirmation table, or lands in _UNMATCHED_LAYERSThe name matched no crosswalk key and no meaning-preserving spelling rule, so it was only proposed — the transfer never applies a proposal by itselfThis is the intended behaviour, not a failure. Confirm the row in match CAD layers and the mapping is remembered for the next drawing. If the name is genuinely a local spelling, confirm it once; if the function does not exist, leave the row unticked and classify it by hand after import. Check the spelling against the Ek-1e function list — Turkish characters are folded for matching, but word order and abbreviations are not.
Imported layers are MPYY feature types instead of the drawing's own CAD layersTR-Only MPYY Style was left onUncheck it. The mode is off by default and is meant for imar plans only; every other source should be imported with it off.
MPYY import stops with "the plan level (UİP / NİP / ÇDP) could not be determined"Plan level is on Auto and the file name carries neither a recognisable marker word nor a scale numberSet the level explicitly in the Plan level selector. The import stops rather than styling the plan as the wrong kind.
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 the MPYY transfer operate only on non-null string values. The transfer's empty-cell policy deliberately leaves a code blank rather than filling it with an invented value, maintaining a clean distinction between “this tabaka is a catalogued function” and “this tabaka was left unresolved”. A blank code is a truthful statement about the input; a plausible-looking invented one is not, and it would survive into any downstream analysis that trusted it.

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 — MPYY Style Bundle

The MPYY transfer draws plan layers with the Ministry's gösterim, rewritten to the MPYY 1.1.7 schema and carried inside the plugin under mpyy/. Three plan levels are covered:

LevelPlanReference scaleSLD styles
UIPUygulama İmar Planı — implementation plan1/100094
NIPNazım İmar Planı — master plan1/500086
CDPÇevre Düzeni Planı — environmental plan1/25,000 and above71

251 styles in total, in mpyy/styles/mpyy_sld/. The bundle also carries what those styles reference: the tarama tiles and the plan symbol fonts and catalogue symbols under mpyy/resources/ (131 font files, 45 catalogue symbols). mpyy/SYNC_MANIFEST.json records the sha256 of every file. No individual colour or width is reproduced here on purpose: the styles are applied from the bundle, and a value transcribed into prose is a value that can silently drift away from the one actually drawn.

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 the official gösterim style set. The plugin ships that symbology rewritten to the MPYY schema, as the bundle under mpyy/.
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.
MPYY transferThe import mode that writes an imar plan's tabaka into MPYY 1.1.7 feature types and draws them with the Ministry's UIP / NIP / CDP styles. Replaced the earlier PlanGML styling mode at 4.0.0.
Plan levelWhich of the three official style sets applies: UIP (implementation plan, 1/1000), NIP (master plan, 1/5000) or CDP (environmental plan, 1/25,000 and above). Auto reads it from the file name.
Plan notationThe drawing's own notation symbols — building-rights circles (nizam / kat, TAKS / KAKS, E =, Yençok) and road-width circles — written to a <file>_PLAN_NOTATION point layer where the planner placed them.
PlanGMLTurkish Ministry's XML-based spatial plan data standard. 02CadGis does not read or write PlanGML documents; the name survives only in the module that resolves a CAD tabaka to its official MPYY identity (core/plangml_schema.py) and in a few internal comments. The user-facing feature is MPYY transfer.
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 MPYY symbology reproduces the official Ministry e-Plan gösterim standards, rewritten to the MPYY 1.1.7 schema; the gösterim itself is the Ministry's and is not claimed as original work here. The MpyyUipDb_2026_02_27.gpkg catalog is compiled and maintained by Yusuf Eminoğlu from the Ministry's published tabaka lists. The style bundle under mpyy/ carries the tarama tiles and the plan symbol fonts those styles reference — among them font files whose redistribution terms are not established; the bundle's own notice records what it contains and does not assert a right to redistribute them. The NCZ decoder shipped in versions 0.1.0 through 4.1.2 was adapted from Jeomatik NCZ Reader (Copyright © 2026 Erdinç Örsan ÜNAL, GPL-2.0-or-later); the current tree carries only 02CadGis's own v2 engine. The vendored olefile library is used under its BSD license for DGN v8 OLE2 reading. Full attribution: THIRD_PARTY_NOTICES.md · THIRD_PARTY_NOTICES.md (GitLab).

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}. The transposition is applied once, at a single point in the decoder, so no downstream consumer sees drawing order. 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 the drawing's SHA-256 and byte size, the Python runtime (version, implementation, platform, processor), warmup and run counts, p50 and p95 parse duration, MiB/s throughput, entities per second, peak Python allocation (via tracemalloc), entity and attribute-table counts, and a normalised output digest. Every measured run is digested, and a run raises rather than reporting if the digests differ — non-deterministic output is a failure, not a benchmark. Defaults are 2 warmups and 7 measured runs; --runs must be at least 3 for the p95 to mean anything. To reproduce:

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

The output digest covers each entity's kind, layer, colour and label, every coordinate to 17 significant digits, and every @TAB cell, so it is sensitive to any decode change at all; the label field is free text for before/after comparison. The synthetic fixture corpus (tests/ncz_fixtures.py) exercises the decoder paths, both block layouts, embedded containers, metadata blocks and @TAB tables. Validation against real municipal drawings is opt-in: set ZERO2CADGIS_NCZ_FIXTURE to a drawing you are licensed to use and the parity test runs against it. That test was last validated on a 1.2 MiB / 8,163-entity municipal Netcad file (60 layers, ITRF / 3° zone 42).

Because the v1 decoder is no longer in the tree, the benchmark compares releases of the v2 engine against each other; the numbers are a regression guard for future work rather than a v1-versus-v2 comparison.

Appendix F — Configuration Reference

02CadGis keeps no configuration file of its own. Everything it remembers between sessions lives either in QGIS's QSettings store or in the two caches described below, and every override it honours is an environment variable. This appendix lists the keys the shipped code actually reads and writes.

QSettings keys

All keys sit in the QSettings scope QGIS itself uses, so they are per-user and survive plugin upgrades.

KeyDefaultDescription
zero2cadgis/oda_converter_path(empty)Path to ODAFileConverter.exe, set through the interactive setup dialog. When present it overrides every automatic ODA discovery path.
zero2cadgis/opts/<widget>(unset)The checked state of each persistent checkbox, stored under that checkbox's own widget name. Written on every toggle; read once when the dock is built. The eleven persisted boxes are chk_conv_simplify, chk_conv_clean, chk_conv_kml_expand, chk_conv_raster, chk_conv_load, chk_ncz_simplify, chk_ncz_clean, chk_ncz_augment, chk_ncz_style, chk_ncz_label and chk_ncz_join. A key with no stored value leaves the widget at its built-in default.
zero2cadgis/opts/ncz_tolerance(widget default)Closure tolerance of the Netcad tab, in drawing units. Persisted on every change.
zero2cadgis/last_import_dir(empty)Folder the last source file was picked from; the next file dialog opens there.
zero2cadgis/last_export_dir(empty)Folder the last export was written to; the next export dialog opens there.

Option state is deliberately per-checkbox rather than one blob, so a key that is missing, unparsable or written by an older version falls back to the widget's own default instead of resetting the whole panel: the reader accepts only true/1 as “checked” and ignores anything it cannot parse.

Environment variables

VariableRead byEffect
ZERO2CADGIS_NCZ_CACHE_DISABLENCZ index cacheSet to 1, true or yes to stop reading and writing the per-drawing NCZ index cache. Every drawing is then indexed from scratch.
ZERO2CADGIS_OGR_CACHE_DISABLEOGR catalog cacheSame values; disables the Geodatabase / database layer-catalog cache.
ZERO2CADGIS_NCZ_FIXTUREtests/test_ncz_engine_v2.pyPath to a real NCZ drawing; the opt-in validation test is skipped unless it is set. No production code path reads it.
ZERO2CADGIS_MPYY_DBtests/test_plangml_schema.pyPath to the Ministry MpyyUipDb GeoPackage; the opt-in catalog test is skipped unless it is set. No production code path reads it.
MPYY_TABAKA_ESLESMELayer-name mappingOverrides the location of the per-user file that remembers confirmed layer-name mappings (see below). Intended for tests and shared workstations.
ODA_FILE_CONVERTER_PATHODA discoveryPath to ODAFileConverter.exe. Consulted during automatic discovery, for CI and containerised environments where the usual install locations are absent.
ODA_PATHODA discoveryAlternative spelling for the ODA installation directory.
ODA_CONVERTERODA discoveryAlternative spelling for the converter executable path.

The three ODA spellings are discovery hints, not overrides: the zero2cadgis/oda_converter_path setting above still wins, so a path set in the dialog is what gets used.

Files and caches written outside QSettings

PathContents
%LOCALAPPDATA%\zero2cadgis\ncz_index\<hash>.jsonThe NCZ index cache: one JSON file per drawing, named by a hash of the drawing's absolute path and keyed to its size and modification time. Falls back to $XDG_CACHE_HOME and then ~/.cache where LOCALAPPDATA is unset. Rebuilt automatically when a drawing changes; Clear cache on the Netcad tab removes it.
<QGIS profile>/mpyy/tabaka_eslesmeleri.jsonThe confirmed layer-name mappings — the ones a person ticked in the match dialog — so the same tabaka name resolves by itself on the next drawing. Written atomically through a temporary file and a rename, so an interrupted write cannot leave a half-file. With no QGIS the fallback is ~/.mpyy/. The file is deliberately shared with the other plugins that carry this module.

Both are caches of one kind or another: deleting either costs time on the next run and nothing else. The mapping file is the exception — it holds decisions a person made, so back it up before clearing a QGIS profile.