fix(ground): 측량 레이어로 운곡교 지형 추출 대상 제한

This commit is contained in:
ypshim committed 2026-11-10 09:54:34 +09:00
1 parent 38854cbe4c
commit 4ef8412d89
5 files changed
+254

No files matched your search

@@ -12,6 +12,8 @@ import numpy as np
from ezdxf import recover
from pyproj import Transformer
from pierzainer_ground.dxf_terrain import _densify,read_source_document
from pierzainer_ground.config import GroundConfig
from pierzainer_ground.dxf_terrain import read_terrain_dxf
from pierzainer_ground.dtm import DTM
ROOT=Path(__file__).resolve().parent.parent
@@ -63,6 +65,33 @@ def read_survey_block(source, project, doc=None):
block=doc.blocks.get(project['terrain_block'])
if block is None:
raise ValueError(f"측량 블록이 없습니다: {project['terrain_block']}")
# A plan's modelspace mixes contours with borehole symbols and design
# outlines that also carry Z. Prefer the established semantic reader when
# this drawing declares known survey layers; retain the block reader for
# original survey XREFs with their own layer conventions.
cfg=GroundConfig(cad_axes=project.get('cad_axes','YX'),use_profile_points=False,
z_min=project.get('z_min',0),z_max=project.get('z_max',200),
contour_step=project['contour_step_m'],dedup_xy=project['dedup_m'])
allowed=cfg.layers.spot_block+cfg.layers.spot_text+cfg.layers.contour
if project.get('layers'):
allowed=tuple(layer for layer in allowed if layer in project['layers'])
if (block.name.lower()=='*model_space' and project.get('prefer_recognized_layers',True)
and any(e.dxf.layer in allowed for e in block)):
cfg.allowed_terrain_layers=allowed
terrain=read_terrain_dxf(source,cfg,document=doc)
a=terrain.points
if project.get('exclude_zero'):
a=a[np.abs(a[:,2])>1e-6]
if len(a)<3:
raise ValueError('인식된 측량 레이어에서 실제 표고점·등고선을 3점 이상 읽지 못했습니다.')
if project.get('terrain_crs') and project.get('crs'):
east,north=Transformer.from_crs(project['terrain_crs'],project['crs'],always_xy=True).transform(a[:,1],a[:,0])
a=np.column_stack([north,east,a[:,2]])
if not np.isfinite(a).all():
raise ValueError('측량 레이어 좌표 변환 결과가 유효하지 않습니다.')
sources=terrain.stats['by_source']
return a,{'semantic_layer_filter':1,'survey_points':sources['spot'],
'spot_text_points':sources['text'],'contour_points':sources['contour']},terrain.stats['contours']
to_model=(Transformer.from_crs(project['terrain_crs'],project['crs'],always_xy=True)
if project.get('terrain_crs') and project.get('crs') else None)
points=[]; contours=[]; types=Counter()
@@ -44,4 +44,27 @@ class SurveyPolylineTests(unittest.TestCase):
points,counts,_=read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
self.assertNotIn('rejected_height_outliers',counts);self.assertEqual(points[:,2].max(),84)
def test_known_plan_layers_exclude_near_height_bore_and_base(self):
doc=ezdxf.new();msp=doc.modelspace()
for y,z in [(0,30),(100,32)]:
msp.add_lwpolyline([(0,y),(100,y)],dxfattribs={'layer':'CAA001','elevation':z})
doc.blocks.new('SPOT').add_circle((0,0),.1)
msp.add_blockref('SPOT',(20,50,31),dxfattribs={'layer':'CA002'})
msp.add_text('30.5',dxfattribs={'layer':'CA0021','insert':(80,50)})
for layer in ['CV-BORE-SYMB','CZ-BASE','CF-BRDG-NEWC']:
msp.add_lwpolyline([(45,45),(55,45),(55,55)],dxfattribs={'layer':layer,'elevation':27.5})
points,counts,_=read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
self.assertGreaterEqual(points[:,2].min(),30)
self.assertEqual(counts['semantic_layer_filter'],1)
self.assertEqual(counts['survey_points'],1)
self.assertEqual(counts['spot_text_points'],1)
self.assertTrue(any(np.array_equal(p,[50,20,31]) for p in points))
self.assertTrue(any(np.array_equal(p,[50,80,30.5]) for p in points))
def test_known_layers_do_not_fall_back_to_symbols_when_empty(self):
doc=ezdxf.new();msp=doc.modelspace()
msp.add_lwpolyline([(0,0),(10,0)],dxfattribs={'layer':'CAA001','elevation':0})
msp.add_lwpolyline([(0,0),(10,0),(10,10)],dxfattribs={'layer':'CV-BORE-SYMB','elevation':28})
with self.assertRaises(ValueError):read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
if __name__=='__main__':unittest.main()