Năm nguyên tắc bất di bất dịch
Mọi quyết định kỹ thuật đều phục vụ năm nguyên tắc này. Khi có mâu thuẫn, nguyên tắc thắng.
Mỗi đối tượng bị bỏ qua phải có lý do ghi lại được: không hình học, hình học rỗng sau khi sửa,
nằm ngoài phạm vi, sai kiểu. Báo cáo nạp luôn nêu đã nạp / đã bỏ qua theo từng lớp.
Con số "đã bỏ qua" khác 0 là cảnh báo cần người xem.
Toàn bộ thuộc tính gốc giữ nguyên 100% trong cột props (JSONB). Cột "typed" chỉ là bản sao
đã ép kiểu để truy vấn và vẽ; ép kiểu thất bại (vd "R8", "D300" vào cột số) thì
cột typed nhận NULL nhưng props vẫn giữ chuỗi gốc.
Luồng bắt buộc: inspect (đọc cấu trúc) → preview (trả GeoJSON hiện trên bản đồ,
không chạm CSDL) → run (ghi). Người vận hành thấy hình học và số lượng trước khi commit.
Mọi thứ về EPSG:4326 khi lưu. Nguồn VN-2000 nắn về WGS-84 một lần duy nhất lúc nạp
bằng 7 tham số Helmert của tỉnh; gói tải xuống chiếu ngược về VN-2000. Không có phép chiếu trung gian nào khác.
"Làm sạch" nghĩa là sửa hình học không hợp lệ, khử nhiễu CAD, bắt điểm theo dung sai đã khai báo.
Không co giãn, xoay, tịnh tiến, làm tròn toạ độ ngoài mức COORDINATE_PRECISION=8 (≈ 1 mm).
Mọi thao tác snapping phải có tham số dung sai rõ ràng và ghi nhật ký.
Tám chặng của quy trình nạp
Mọi định dạng đầu vào đều đi qua đúng tám chặng. Khác biệt giữa các định dạng nằm ở chặng 2–4;
từ chặng 5 dòng dữ liệu là một FeatureCollection GeoJSON WGS-84 thống nhất.
Chặng 4 & 5 tạo ra khác biệt: cùng một tuyến đường, đến từ .gdb thì đã đúng lớp
đúng cột; đến từ .dxf thì phải suy ra từ tên lớp CAD và tự polygonize.
Tiếp nhận & nhận diện nguồn
File tải lên lưu vào thư mục phiên _incoming/<token>/ kèm giới hạn dung lượng
(MAX_GDB_MB). Đuôi file quyết định bước chuẩn bị nhưng vẫn để OGR tự xác nhận driver ở chặng thanh tra.
| Đầu vào | Bước chuẩn bị | Nguồn OGR | Driver |
|---|---|---|---|
| .zip | Giải nén, tìm theo ưu tiên: *.gdb/ → *.shp → geojson/gpkg/kml/tab/dxf/csv | File đầu tiên khớp | tự động |
| .gdb (.zip) | Giải nén, lấy thư mục .gdb đầu tiên | Thư mục .gdb | OpenFileGDB |
| .kmz | Giải nén, lấy *.kml đầu tiên | File .kml | LIBKML/KML |
| .dxf / .dwg | Giữ nguyên | File gốc | CAD, hạ cấp DXF |
| .shp | Cần đủ .dbf .shx .prj .cpg đi kèm | File .shp | ESRI Shapefile |
| .geojson .json .gpkg .kml .tab | Giữ nguyên | File gốc | tự động |
| .csv .xlsx | Giữ nguyên | File gốc | CSV / XLSX |
Người dùng hay chỉ gửi mỗi .shp. Không có .dbf thì mất toàn bộ thuộc tính;
không có .prj thì mất CRS. Xử lý: luôn yêu cầu gửi shapefile trong .zip;
thấy .shp đơn lẻ thì báo rõ "thiếu .dbf/.prj" thay vì nạp im lặng.
Thanh tra: đọc trước khi động vào
ogrinfo -ro -so -json cho toàn bộ cấu trúc: danh sách lớp, kiểu hình học, số đối tượng,
danh sách trường, WKT hệ toạ độ.
Rút CRS từ WKT
Regex bắt ID["EPSG",xxxx] ở cuối chuỗi WKT. Có mã EPSG → dùng thẳng. Chỉ có WKT không mã →
đánh dấu "wkt". Không có gì → has_crs=false, hỏi người dùng chọn kinh tuyến trục.
Nhánh CAD: bóc tách theo lớp bản vẽ
DXF/DWG thường chỉ có một lớp OGR tên entities. Truy vấn SQLite gom theo trường
"Layer" và "SubClasses" để dựng bảng phân rã cho bộ phân loại tự động.
SELECT "Layer" L, "SubClasses" SC, GeometryType(geometry) GT, count(*) N
FROM entities GROUP BY L, SC, GT;
| SubClass AutoCAD | Vai trò | Ý nghĩa |
|---|---|---|
| AcDbHatch, AcDbFace | polygon | Vùng tô — ranh lô, khu chức năng |
| AcDbPolyline, AcDbLine, AcDbSpline, AcDbArc, AcDbCircle | line | Tuyến — chỉ giới, tim đường, hạ tầng |
| AcDbPoint, AcDbBlockReference | point / block | Điểm — mốc, trạm, cột |
| AcDbText, AcDbMText, AcDbAttribute* | text | Nhãn — không là đối tượng địa lý, chỉ gán thuộc tính |
| AcDbDimension, AcDbLeader, AcDbMLeader | junk | Kích thước, đường dẫn chú thích — loại bỏ |
Phân loại & ánh xạ vào 153 lớp chuẩn
Kho dữ liệu cố định: 153 feature class, 2 142 cột, dựng sẵn theo bốn file mẫu
HienTrang / MocGioi / NenDiaHinh / QuyHoach.gdb. Nạp thêm chỉ được rót vào một trong các lớp
này — không tạo lớp ngoài chuẩn. Bảng phi không gian đi vào kho chung x_table.
Nguồn đã đúng chuẩn (GDB / GPKG / SHP đặt tên chuẩn)
Ánh xạ theo tên feature class. Trùng khớp fc_name → chọn sẵn lớp đích, người vận hành xác nhận.
Nguồn tự do (CAD / KML / GeoJSON không theo chuẩn)
Dùng bộ luật cad_rules.yml. Mỗi luật khớp theo chuỗi con trong tên lớp và trả về:
role— keep (nạp), annotation (làm nhãn), ignore (bỏ), unmatched (chờ chọn).target— lớp đích<Nhóm>/<FcName>.force_geom— ép kiểu hình học.polygonize— nối LINESTRING khép kín thành POLYGON.phanloai— gánphanLoaitheo từ khoá trong tên lớp.duongkinh_from_name— rútD300,Ø200từ tên lớp vàoduongKinh.
unmatched để trống lớp đích, buộc người vận hành chọn tay hoặc bỏ qua. Không đoán bừa —
thà thiếu một lớp còn hơn có một lớp sai nằm lẫn trong CSDL.
Chuẩn hoá tên trường
Shapefile cắt tên còn 10 ký tự; ArcGIS xuất PascalCase. Bảng _FIELD_ALIASES + hàm
_norm ánh xạ mọi biến thể về tên cột chuẩn. Giá trị gốc vẫn nằm nguyên trong props.
"8" -> 8.0
"1 631 234,56" -> 1631234.56 # bỏ khoảng trắng, "," -> "."
"R8" "D300" -> NULL (cột typed) # giữ "R8" trong props.banKinh
"25/12/2025" -> "2025-12-25" # dd/mm/yyyy -> ISO
"(null)" "" -> NULL
Làm sạch hình học & nắn toạ độ
Chuyển đổi bằng ogr2ogr — bộ cờ chuẩn
ogr2ogr -f GeoJSON out.geojson SOURCE LAYER \
-s_srs "<CRS nguồn>" -t_srs EPSG:4326 \
-nlt PROMOTE_TO_MULTI \ # đồng nhất Multi*
-makevalid \ # SỬA hình học lỗi, không bỏ
-lco COORDINATE_PRECISION=8 \ # ~1 mm
-lco RFC7946=NO \
-mapFieldType DateTime=String,Date=String,Time=String,\
IntegerList=String,RealList=String,StringList=String \
-skipfailures # 1 feature hỏng không giết cả lớp
Nếu -makevalid lỗi ở OGR cũ → chạy lại không có cờ đó. Nếu kết quả rỗng và nguồn
không có CRS → thử lại -a_srs EPSG:4326 (coi toạ độ như đã là kinh/vĩ độ).
VN-2000 → WGS-84: một phép nắn duy nhất
Ba kinh tuyến trục: 108°00′ (EPSG:5898, mặc định Quảng Ngãi), 107°45′, 107°30′.
+proj=tmerc +lat_0=0 +lon_0=108 +k=0.9999 +x_0=500000 +y_0=0
+ellps=WGS84
+towgs84=-191.90441429,-39.30318279,-111.45032835,
-0.00928836,0.01975479,-0.00427372,0.252906278
+units=m +no_defs
File CAD gần như không bao giờ mang CRS. Chọn nhầm 107°45′ cho dữ liệu vẽ theo 108° thì cả đồ án lệch ~1–2 km về phía đông. Xử lý: ở bước xem trước chồng lên nền bản đồ — lệch KTT lộ ra ngay; thêm kiểm tra biên độ toạ độ X (500 000 ± vài chục km) để cảnh báo tự động.
Xử lý hình học trong PostGIS (khi gộp / polygonize)
| Tình huống | Hàm | Ghi chú |
|---|---|---|
| Vòng LINESTRING khép kín → vùng | ST_Polygonize(ST_Collect(ST_MakeValid(…))) | Dựng vùng từ mạng tuyến CAD |
| Nối nhiều tuyến rời thành 1 | ST_LineMerge(ST_UnaryUnion(ST_Collect(g))) | "1 tuyến = 1 đối tượng" |
| Hợp nhiều vùng thành 1 | ST_UnaryUnion(ST_Collect(g)) | Giữ thuộc tính chung |
| Gộp điểm | ST_CollectionHomogenize(ST_Collect(g)) | ST_MakeValid lỗi với POINT ở bản này |
| GEOMETRYCOLLECTION / CircularString từ makevalid | ST_CollectionExtract(ST_CurveToLine(geom), dim) | Ép về kiểu đơn theo FC đích |
Bảng tra nhanh theo định dạng
| Định dạng | CRS đến từ đâu | Rác / rủi ro | Xử lý bắt buộc |
|---|---|---|---|
| DXF / DWG | Không có. Chọn KTT. | Dimension & leader lẫn vào tuyến; text hiểu thành điểm; polyline hở không thành vùng; block lồng hình học; Z rác; đơn vị mm/cm lẫn m. | Bóc theo lớp CAD; loại junk; text → annotation; polygonize; force_geom; kiểm biên độ toạ độ. |
| SHP (.zip) | .prj. Không có → hỏi. |
Tên trường cắt 10 ký tự; encoding .dbf sai → tiếng Việt vỡ; ranh giới nhiều phần bị tách; đỉnh trùng. |
Gửi kèm .cpg/.prj; _FIELD_ALIASES; PROMOTE_TO_MULTI; -makevalid. |
| GeoJSON | Luôn WGS-84. | Đôi khi mang toạ độ mét chưa reproject; polygon quấn ngược chiều; null geometry; thuộc tính lồng object. |
Kiểm biên độ toạ độ (>180 ⇒ chưa reproject); phẳng hoá thuộc tính lồng vào props. |
| KML / KMZ | Luôn WGS-84. | Thuộc tính nằm trong HTML mô tả; MultiGeometry trộn kiểu; style lẫn dữ liệu; placemark rỗng. | Bóc bảng thuộc tính từ ExtendedData; tách kiểu bằng geom_kind; loại placemark không hình học. |
| GPKG | Bảng gpkg_spatial_ref_sys — đáng tin. |
Nhiều lớp trong 1 file; lớp aspatial lẫn spatial; trigger vướng khi đọc nhanh. | Liệt kê toàn bộ lớp ở thanh tra; lớp aspatial → x_table. |
| GDB (.zip) | WKT metadata lớp — chính xác nhất. | Feature dataset lồng nhau; domain coded-value; quan hệ (relationship class); subtype; cột SHAPE_Length/Area tự sinh. |
Đọc dataset để giữ nhóm; áp domain để giải mã coded-value; quan hệ & bảng → x_table. |
| CSV | Không có. Cần cột toạ độ hoặc WKT. | Dấu phân cách lẫn (,/;/tab); BOM đầu file; số kiểu Việt 1.234,5; tiêu đề kép; ô trống vs "0". |
Auto-detect delimiter + đọc utf-8-sig; khai báo cột X/Y hoặc WKT + CRS; bỏ dòng nhãn tiếng Việt. |
| XLSX | Không có (như CSV). | Nhiều sheet; ô gộp; công thức chưa tính giá trị; ngày Excel serial; hàng/cột trống chèn giữa. | Chọn sheet rõ ràng; đọc data_only; bỏ hàng rỗng; ngày serial → ISO. |
Phân loại dữ liệu rác & cách xử lý
"Rác" chia làm ba mức. Đỏ phải chặn hoặc sửa trước khi nạp; vàng nạp được nhưng phải ghi cảnh báo; xanh xử lý tự động.
Hình học tự cắt / vòng hở
Polygon biên tự giao; polyline "gần khép" đầu–cuối cách vài cm.
Sửa: ST_MakeValid cho tự cắt; bắt điểm đầu–cuối theo dung sai (đề xuất 0,02 m) rồi ST_Polygonize.
Hình học rỗng sau khi sửa
Polygon suy biến, tuyến độ dài 0, điểm trùng nhau hoàn toàn.
Sửa: loại bỏ, ghi vào danh sách bị bỏ kèm lý do. Không đếm vào "đã nạp".
Toạ độ ngoài miền
X không quanh 500 000; điểm rơi ra biển; đơn vị mm lẫn m khiến vật to gấp 1000 lần.
Sửa: kiểm biên độ bounding-box trước khi nạp; lệch > ngưỡng → chặn, báo "kiểm tra lại KTT / đơn vị".
Nhiễu CAD
Dimension, leader, mtext, hatch trang trí, khung bản vẽ, ghi chú kỹ thuật.
Sửa: phân rã theo SubClasses → junk; lớp tên "GHICHU"/"KHUNG"/"TITLE" → role: ignore.
Đỉnh trùng & sliver
Cạnh lô hàng chục đỉnh cách nhau < 1 mm; mảnh vùng < 0,5 m² kẹp giữa hai lô.
Sửa: ST_SnapToGrid theo lưới dung sai; lọc vùng theo ngưỡng diện tích tối thiểu, báo cáo số bị lọc.
Trùng lặp đối tượng
Cùng tuyến vẽ hai lần chồng khít; feature lặp do nhập nhiều lần.
Sửa: hash hình học đã snap + khoá thuộc tính; trùng → giữ 1, ghi log số bản sao đã loại.
Thuộc tính "gần rỗng"
"(null)", "N/A", "-", khoảng trắng, "#".
Sửa: danh sách token rỗng → NULL ở cột typed; vẫn giữ nguyên trong props.
Toạ độ Z thừa
File CAD/GDB mang cao độ Z trong khi bảng geom là 2D.
Tự động: ST_Force2D ở mọi lối ghi. Cao độ thật nằm ở cột caoDo*.
Kiểu hình học hỗn hợp
Lớp lẫn Polygon + MultiPolygon; KML MultiGeometry trộn line và point.
Tự động: PROMOTE_TO_MULTI; lọc theo geom_kind đã chọn.
Sai kiểu giá trị
"R8" vào cột số, "12,5" phẩy thập phân, ngày dd/mm/yyyy.
Tự động (khi NẠP HÀNG LOẠT): ép mềm — fail thì NULL ở cột typed, props giữ gốc. Khi SỬA TAY trên bảng: nghiêm ngặt — báo lỗi, không cho lưu sai kiểu.
Encoding tiếng Việt
DBF Windows-1258, CSV có BOM, XLSX ô chuỗi lẫn số.
Tự động: đọc utf-8-sig; tôn trọng .cpg; OGR -oo ENCODING=.
Feature không hình học
Placemark rỗng, dòng CSV thiếu toạ độ, bảng quan hệ trong GDB.
Tự động: có bảng thuộc tính → x_table; thật sự rỗng → bỏ qua, đếm vào "đã bỏ qua".
Cổng kiểm soát chất lượng & nghiệm thu
Sau chặng nạp, báo cáo nghiệm thu đối chiếu nguồn với đích. Ngưỡng dưới là gợi ý khởi điểm — mọi lần vượt ngưỡng phải có người xác nhận.
- Đối soát số lượng|nguồn − đích| = đã bỏ qua Số feature nguồn trừ số đã nạp phải bằng đúng số ghi trong "đã bỏ qua". Chênh không giải thích được ⇒ dừng.
- Hình học hợp lệ≥ 99,5 %
ST_IsValidtrên toàn lớp sau khi nạp. Phần còn lại phải nằm trong log makevalid. - Độ đầy cột khoámaDoiTuong ≥ 95 % Cột định danh phải gần đầy; rỗng nhiều ⇒ nguồn thiếu hoặc ánh xạ sai tên trường.
- Biên độ toạ độX = 500 000 ± 80 km Bounding-box lớp sau khi nắn phải nằm trong phạm vi hành chính tỉnh.
- Trùng lặp= 0 cặp trùng khít Không còn feature trùng hình học + khoá thuộc tính sau khi khử.
- Topology lớp vùng0 overlap · gap < ngưỡng Với lớp phủ kín: không chồng lấn; khe hở nhỏ hơn dung sai bắt điểm.
- Bảo toàn thuộc tính gốcprops ⊇ mọi trường nguồn
Mọi tên trường của nguồn xuất hiện trong
propsít nhất một dòng.
Lộ trình nâng cấp — nạp thông minh hơn
Quy trình hiện tại đủ chắc để không mất dữ liệu. Mười hạng mục sau nâng nó lên "tự động hoá cao, chính xác kiểm chứng được".
Nạp vào bảng tạm trước, so khớp theo maDoiTuong, sinh báo cáo thêm / sửa / xoá.
Người vận hành duyệt bản diff rồi mới commit.
Khai báo dung sai bắt điểm cho từng nhóm lớp (ranh lô 0,02 m; tuyến hạ tầng 0,05 m; mốc 0). Dùng
ST_Snap/ST_SnapToGrid khử đỉnh trùng, khép vòng, làm khít ranh giới chung —
chỉ trong dung sai đã ký, ghi số đỉnh bị dịch.
Hash hình học chuẩn hoá + khoá thuộc tính. Trùng khít → giữ một; trùng một phần → đánh dấu để xử lý.
Với lớp phủ kín: quét overlap, gap, sliver, dangle ngay trong bước xem trước và tô đỏ trên bản đồ — thấy lỗi trước khi ghi.
Sửa cad_rules.yml qua giao diện; học từ lịch sử: lớp CAD tên tương tự → gợi ý lớp đích đã dùng.
Nạp nhiều lớp/file cùng lúc qua hàng đợi worker, tiến độ realtime. GDB lớn không khoá cả phiên.
Mỗi feature ghi: file nguồn, lớp nguồn, phiên nạp, người nạp, thời điểm, bộ cờ ogr2ogr đã dùng.
Tự dựng từ §07: đối soát số lượng, % hình học hợp lệ, độ đầy cột, danh sách bị bỏ kèm lý do, ảnh bản đồ trước/sau. Đính kèm hồ sơ đồ án.
Đọc domain File Geodatabase, thay giá trị số bằng nhãn (1 → "Đất ở đô thị").
Từ biên độ toạ độ và mật độ đỉnh, đoán đơn vị (m/mm) và kinh tuyến trục, đề xuất sẵn — giảm hẳn lỗi lệch KTT.