@liuhange/dsh-underground-pipeline-inspector 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,80 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "lastUpdated": "2026-10-01",
4
+ "diameterRange": {
5
+ "description": "管径值域,单位毫米",
6
+ "minMm": 0,
7
+ "maxMm": 3000,
8
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.3.4条"
9
+ },
10
+ "materialEnum": {
11
+ "description": "管材材质枚举",
12
+ "allowedValues": [
13
+ "钢管",
14
+ "铸铁管",
15
+ "球墨铸铁管",
16
+ "钢筋混凝土管",
17
+ "混凝土管",
18
+ "陶土管",
19
+ "PVC管",
20
+ "PE管",
21
+ "HDPE管",
22
+ "玻璃钢管",
23
+ "塑料管",
24
+ "其他"
25
+ ],
26
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.3.5条"
27
+ },
28
+ "buryMethodEnum": {
29
+ "description": "埋设方式枚举",
30
+ "allowedValues": [
31
+ "直埋",
32
+ "管沟",
33
+ "顶管",
34
+ "拖拉管",
35
+ "盾构",
36
+ "其他"
37
+ ],
38
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.3.6条"
39
+ },
40
+ "flowDirectionEnum": {
41
+ "description": "排水流向枚举",
42
+ "allowedValues": [
43
+ "顺流",
44
+ "逆流",
45
+ "未知"
46
+ ],
47
+ "policyBasis": "依据:《城镇排水管渠运行维护及安全技术规程》(CJJ 68-2016)第3.2.4条"
48
+ },
49
+ "attributeSpec": {
50
+ "description": "属性项规范,字段名称与最大长度约束",
51
+ "fieldConstraints": [
52
+ {
53
+ "fieldName": "pointId",
54
+ "maxLength": 32,
55
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.2.1条"
56
+ },
57
+ {
58
+ "fieldName": "segmentId",
59
+ "maxLength": 32,
60
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.2.2条"
61
+ },
62
+ {
63
+ "fieldName": "pointType",
64
+ "maxLength": 16,
65
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.2.3条"
66
+ },
67
+ {
68
+ "fieldName": "material",
69
+ "maxLength": 16,
70
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.3.5条"
71
+ },
72
+ {
73
+ "fieldName": "buryMethod",
74
+ "maxLength": 16,
75
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.3.6条"
76
+ }
77
+ ],
78
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.2条"
79
+ }
80
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "lastUpdated": "2026-10-01",
4
+ "workspace": {
5
+ "description": "巡检工作区范围定义,含图层名称与边界",
6
+ "requiredLayers": [
7
+ "pipeline_point",
8
+ "pipeline_segment",
9
+ "pipeline_structure"
10
+ ],
11
+ "policyBasis": "依据:《地下管线数据获取规程》(GB/T 35644-2017)第5.1条"
12
+ },
13
+ "edgeMatching": {
14
+ "description": "接边点坐标容差,单位米",
15
+ "toleranceMeter": 0.005,
16
+ "policyBasis": "依据:《城市地下管线探测技术规程》(CJJ 61-2017)第4.6.2条"
17
+ },
18
+ "legalCoordinateSystems": {
19
+ "description": "合法坐标系枚举",
20
+ "allowedSridList": [
21
+ "CGCS2000_3_degree_GK_Zone_38",
22
+ "CGCS2000_3_degree_GK_Zone_39",
23
+ "CGCS2000_3_degree_GK_Zone_40",
24
+ "CGCS2000"
25
+ ],
26
+ "policyBasis": "依据:《地下管线数据获取规程》(GB/T 35644-2017)第5.2.2条"
27
+ },
28
+ "verticalDatum": {
29
+ "description": "合法高程基准枚举",
30
+ "allowedDatumList": [
31
+ "1985国家高程基准",
32
+ "1956黄海高程系",
33
+ "地方独立高程基准"
34
+ ],
35
+ "policyBasis": "依据:《地下管线数据获取规程》(GB/T 35644-2017)第5.2.3条"
36
+ },
37
+ "connectivity": {
38
+ "description": "连通性要求,管线点最小连通管段数与最大连通管段数",
39
+ "minConnectedSegments": 1,
40
+ "maxConnectedSegments": 4,
41
+ "policyBasis": "依据:《地下管线数据获取规程》(GB/T 35644-2017)第6.3条"
42
+ },
43
+ "grossErrorRate": {
44
+ "description": "管线点粗差率阈值,超过则不合格",
45
+ "thresholdRate": 0.05,
46
+ "policyBasis": "依据:《广东省地下管线数据检查导则》第7.3.11条"
47
+ },
48
+ "fieldIntegrity": {
49
+ "description": "管线点与管段必填字段清单",
50
+ "pipelinePointRequiredFields": [
51
+ "pointId",
52
+ "pointType",
53
+ "x",
54
+ "y",
55
+ "elevation"
56
+ ],
57
+ "pipelineSegmentRequiredFields": [
58
+ "segmentId",
59
+ "startPointId",
60
+ "endPointId",
61
+ "diameter",
62
+ "material",
63
+ "buryMethod"
64
+ ],
65
+ "policyBasis": "依据:《信息技术 地下管线数据交换技术要求》(GB/T 29806-2013)第6.2条"
66
+ }
67
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "lastUpdated": "2026-10-01",
4
+ "qualityElements": {
5
+ "description": "六类质量元素及权重,等权配置",
6
+ "elements": [
7
+ {
8
+ "elementName": "空间参考系",
9
+ "weight": 0.1667,
10
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.1条"
11
+ },
12
+ {
13
+ "elementName": "位置精度",
14
+ "weight": 0.1667,
15
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.2条"
16
+ },
17
+ {
18
+ "elementName": "逻辑一致性",
19
+ "weight": 0.1667,
20
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.3条"
21
+ },
22
+ {
23
+ "elementName": "时间精度",
24
+ "weight": 0.1667,
25
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.4条"
26
+ },
27
+ {
28
+ "elementName": "栅格质量",
29
+ "weight": 0.1666,
30
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.5条"
31
+ },
32
+ {
33
+ "elementName": "附件质量",
34
+ "weight": 0.1666,
35
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6.6条"
36
+ }
37
+ ],
38
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第6章"
39
+ },
40
+ "errorClassThresholds": {
41
+ "description": "A/B/C/D错误分类扣分阈值,A类最严重",
42
+ "classAScoreDeduction": 1.0,
43
+ "classBScoreDeduction": 0.6,
44
+ "classCScoreDeduction": 0.3,
45
+ "classDScoreDeduction": 0.1,
46
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第7.2条"
47
+ },
48
+ "qualityGradeThresholds": {
49
+ "description": "质量等级划分阈值,合格分下限",
50
+ "excellentMinScore": 90,
51
+ "goodMinScore": 80,
52
+ "qualifiedMinScore": 70,
53
+ "policyBasis": "依据:《测绘成果质量检查与验收》(GB/T 24356-2023)第8.1条"
54
+ }
55
+ }
@@ -0,0 +1,9 @@
1
+ # Cordis Framework Patch Declaration for @liuhange/dsh-underground-pipeline-inspector
2
+ # This file declares the plugin's runtime patch for the Cordis framework.
3
+ # Used by DSH plugin manager to apply framework-level patches during installation.
4
+ plugin: @liuhange/dsh-underground-pipeline-inspector
5
+ version: 1.0.0
6
+ patch:
7
+ - target: tools
8
+ action: register
9
+ description: Register plugin tools into Cordis runtime
@@ -0,0 +1,108 @@
1
+ export class AttributePrecisionChecker {
2
+ check(dataset, config) {
3
+ const checkResults = [];
4
+ const invalidDiameter = [];
5
+ const invalidMaterial = [];
6
+ const invalidBuryMethod = [];
7
+ const invalidFlowDirection = [];
8
+ const fieldLengthViolations = [];
9
+ const materialSet = new Set(config.materialEnum.allowedValues);
10
+ const buryMethodSet = new Set(config.buryMethodEnum.allowedValues);
11
+ const flowDirectionSet = new Set(config.flowDirectionEnum.allowedValues);
12
+ const constraintMap = new Map();
13
+ for (const constraint of config.attributeSpec.fieldConstraints) {
14
+ constraintMap.set(constraint.fieldName, constraint.maxLength);
15
+ }
16
+ for (const segment of dataset.segments) {
17
+ if (segment.diameter < config.diameterRange.minMm ||
18
+ segment.diameter > config.diameterRange.maxMm) {
19
+ invalidDiameter.push({
20
+ segmentId: segment.segmentId,
21
+ description: `管段 ${segment.segmentId} 管径 ${segment.diameter} 不在值域 [${config.diameterRange.minMm}, ${config.diameterRange.maxMm}] 内`,
22
+ });
23
+ checkResults.push({
24
+ checkName: '管径值域检查',
25
+ errorClass: 'C',
26
+ objectId: segment.segmentId,
27
+ description: `管段 ${segment.segmentId} 管径 ${segment.diameter} 不在值域 [${config.diameterRange.minMm}, ${config.diameterRange.maxMm}] 内`,
28
+ policyBasis: config.diameterRange.policyBasis,
29
+ });
30
+ }
31
+ if (!materialSet.has(segment.material)) {
32
+ invalidMaterial.push({
33
+ segmentId: segment.segmentId,
34
+ description: `管段 ${segment.segmentId} 材质 ${segment.material} 不在合法枚举中`,
35
+ });
36
+ checkResults.push({
37
+ checkName: '材质枚举检查',
38
+ errorClass: 'C',
39
+ objectId: segment.segmentId,
40
+ description: `管段 ${segment.segmentId} 材质 ${segment.material} 不在合法枚举中`,
41
+ policyBasis: config.materialEnum.policyBasis,
42
+ });
43
+ }
44
+ if (!buryMethodSet.has(segment.buryMethod)) {
45
+ invalidBuryMethod.push({
46
+ segmentId: segment.segmentId,
47
+ description: `管段 ${segment.segmentId} 埋设方式 ${segment.buryMethod} 不在合法枚举中`,
48
+ });
49
+ checkResults.push({
50
+ checkName: '埋设方式枚举检查',
51
+ errorClass: 'C',
52
+ objectId: segment.segmentId,
53
+ description: `管段 ${segment.segmentId} 埋设方式 ${segment.buryMethod} 不在合法枚举中`,
54
+ policyBasis: config.buryMethodEnum.policyBasis,
55
+ });
56
+ }
57
+ if (segment.flowDirection !== undefined && !flowDirectionSet.has(segment.flowDirection)) {
58
+ invalidFlowDirection.push({
59
+ segmentId: segment.segmentId,
60
+ description: `管段 ${segment.segmentId} 流向 ${segment.flowDirection} 不在合法枚举中`,
61
+ });
62
+ checkResults.push({
63
+ checkName: '流向枚举检查',
64
+ errorClass: 'C',
65
+ objectId: segment.segmentId,
66
+ description: `管段 ${segment.segmentId} 流向 ${segment.flowDirection} 不在合法枚举中`,
67
+ policyBasis: config.flowDirectionEnum.policyBasis,
68
+ });
69
+ }
70
+ this.checkFieldLength(segment.segmentId, 'segmentId', segment.segmentId, constraintMap, fieldLengthViolations, checkResults, config.attributeSpec.policyBasis);
71
+ this.checkFieldLength(segment.segmentId, 'material', segment.material, constraintMap, fieldLengthViolations, checkResults, config.attributeSpec.policyBasis);
72
+ this.checkFieldLength(segment.segmentId, 'buryMethod', segment.buryMethod, constraintMap, fieldLengthViolations, checkResults, config.attributeSpec.policyBasis);
73
+ }
74
+ for (const point of dataset.points) {
75
+ this.checkFieldLength(point.pointId, 'pointId', point.pointId, constraintMap, fieldLengthViolations, checkResults, config.attributeSpec.policyBasis);
76
+ this.checkFieldLength(point.pointId, 'pointType', point.pointType, constraintMap, fieldLengthViolations, checkResults, config.attributeSpec.policyBasis);
77
+ }
78
+ const attributeResult = {
79
+ invalidDiameter,
80
+ invalidMaterial,
81
+ invalidBuryMethod,
82
+ invalidFlowDirection,
83
+ fieldLengthViolations,
84
+ policyBasis: config.attributeSpec.policyBasis,
85
+ };
86
+ return { attributeResult, checkResults };
87
+ }
88
+ checkFieldLength(objectId, fieldName, value, constraintMap, violations, checkResults, policyBasis) {
89
+ const maxLength = constraintMap.get(fieldName);
90
+ if (maxLength === undefined)
91
+ return;
92
+ if (value.length > maxLength) {
93
+ violations.push({
94
+ objectId,
95
+ fieldName,
96
+ description: `对象 ${objectId} 字段 ${fieldName} 长度 ${value.length} 超过最大长度 ${maxLength}`,
97
+ });
98
+ checkResults.push({
99
+ checkName: '属性项规范检查',
100
+ errorClass: 'C',
101
+ objectId,
102
+ description: `对象 ${objectId} 字段 ${fieldName} 长度 ${value.length} 超过最大长度 ${maxLength}`,
103
+ policyBasis,
104
+ });
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=attribute-precision-checker.js.map
@@ -0,0 +1,44 @@
1
+ export class CoordinateChecker {
2
+ check(dataset, config) {
3
+ const checkResults = [];
4
+ const missingCoordinatePoints = [];
5
+ const pointMap = new Map();
6
+ for (const point of dataset.points) {
7
+ pointMap.set(point.pointId, true);
8
+ }
9
+ for (const segment of dataset.segments) {
10
+ if (!pointMap.has(segment.startPointId)) {
11
+ missingCoordinatePoints.push({
12
+ pointId: segment.startPointId,
13
+ description: `管段 ${segment.segmentId} 起点引用 ${segment.startPointId} 不存在,无法定位坐标`,
14
+ });
15
+ checkResults.push({
16
+ checkName: '缺坐标检查',
17
+ errorClass: 'B',
18
+ objectId: segment.segmentId,
19
+ description: `管段 ${segment.segmentId} 起点引用 ${segment.startPointId} 不存在,无法定位坐标`,
20
+ policyBasis: config.fieldIntegrity.policyBasis,
21
+ });
22
+ }
23
+ if (!pointMap.has(segment.endPointId)) {
24
+ missingCoordinatePoints.push({
25
+ pointId: segment.endPointId,
26
+ description: `管段 ${segment.segmentId} 终点引用 ${segment.endPointId} 不存在,无法定位坐标`,
27
+ });
28
+ checkResults.push({
29
+ checkName: '缺坐标检查',
30
+ errorClass: 'B',
31
+ objectId: segment.segmentId,
32
+ description: `管段 ${segment.segmentId} 终点引用 ${segment.endPointId} 不存在,无法定位坐标`,
33
+ policyBasis: config.fieldIntegrity.policyBasis,
34
+ });
35
+ }
36
+ }
37
+ const coordinateResult = {
38
+ missingCoordinatePoints,
39
+ policyBasis: config.fieldIntegrity.policyBasis,
40
+ };
41
+ return { coordinateResult, checkResults };
42
+ }
43
+ }
44
+ //# sourceMappingURL=coordinate-checker.js.map
@@ -0,0 +1,83 @@
1
+ export class CoverageChecker {
2
+ check(dataset, config) {
3
+ const checkResults = [];
4
+ const missingLayers = [];
5
+ const fieldErrors = [];
6
+ const presentLayers = new Set(dataset.workspaceLayers ?? []);
7
+ for (const requiredLayer of config.workspace.requiredLayers) {
8
+ if (!presentLayers.has(requiredLayer)) {
9
+ missingLayers.push(requiredLayer);
10
+ checkResults.push({
11
+ checkName: '工作区图层覆盖检查',
12
+ errorClass: 'B',
13
+ objectId: requiredLayer,
14
+ description: `工作区缺少必需图层: ${requiredLayer}`,
15
+ policyBasis: config.workspace.policyBasis,
16
+ });
17
+ }
18
+ }
19
+ for (const point of dataset.points) {
20
+ const missing = this.checkPointFields(point, config.fieldIntegrity.pipelinePointRequiredFields);
21
+ if (missing.length > 0) {
22
+ fieldErrors.push({
23
+ objectId: point.pointId,
24
+ missingFields: missing,
25
+ errorMessage: '管线点必填字段缺失',
26
+ });
27
+ checkResults.push({
28
+ checkName: '管线点字段完整性检查',
29
+ errorClass: 'B',
30
+ objectId: point.pointId,
31
+ description: `管线点 ${point.pointId} 缺少字段: ${missing.join(', ')}`,
32
+ policyBasis: config.fieldIntegrity.policyBasis,
33
+ });
34
+ }
35
+ }
36
+ for (const segment of dataset.segments) {
37
+ const missing = this.checkSegmentFields(segment, config.fieldIntegrity.pipelineSegmentRequiredFields);
38
+ if (missing.length > 0) {
39
+ fieldErrors.push({
40
+ objectId: segment.segmentId,
41
+ missingFields: missing,
42
+ errorMessage: '管段必填字段缺失',
43
+ });
44
+ checkResults.push({
45
+ checkName: '管段字段完整性检查',
46
+ errorClass: 'B',
47
+ objectId: segment.segmentId,
48
+ description: `管段 ${segment.segmentId} 缺少字段: ${missing.join(', ')}`,
49
+ policyBasis: config.fieldIntegrity.policyBasis,
50
+ });
51
+ }
52
+ }
53
+ const coverageResult = {
54
+ missingLayers,
55
+ fieldErrors,
56
+ policyBasis: config.workspace.policyBasis,
57
+ };
58
+ return { coverageResult, checkResults };
59
+ }
60
+ checkPointFields(point, requiredFields) {
61
+ const missing = [];
62
+ const obj = point;
63
+ for (const field of requiredFields) {
64
+ const value = obj[field];
65
+ if (value === null || value === undefined || value === '') {
66
+ missing.push(field);
67
+ }
68
+ }
69
+ return missing;
70
+ }
71
+ checkSegmentFields(segment, requiredFields) {
72
+ const missing = [];
73
+ const obj = segment;
74
+ for (const field of requiredFields) {
75
+ const value = obj[field];
76
+ if (value === null || value === undefined || value === '') {
77
+ missing.push(field);
78
+ }
79
+ }
80
+ return missing;
81
+ }
82
+ }
83
+ //# sourceMappingURL=coverage-checker.js.map
@@ -0,0 +1,42 @@
1
+ export class EdgeMatchingChecker {
2
+ check(points, config) {
3
+ const checkResults = [];
4
+ const mismatchedPairs = [];
5
+ const tolerance = config.edgeMatching.toleranceMeter;
6
+ const neighborThreshold = tolerance * 100;
7
+ for (let i = 0; i < points.length; i++) {
8
+ for (let j = i + 1; j < points.length; j++) {
9
+ const pointA = points[i];
10
+ const pointB = points[j];
11
+ if (pointA.pointId === pointB.pointId)
12
+ continue;
13
+ const distance = this.calculateDistance(pointA, pointB);
14
+ if (distance <= neighborThreshold && distance > tolerance) {
15
+ mismatchedPairs.push({
16
+ pointIdA: pointA.pointId,
17
+ pointIdB: pointB.pointId,
18
+ distance,
19
+ });
20
+ checkResults.push({
21
+ checkName: '接边点一致性检查',
22
+ errorClass: 'B',
23
+ objectId: `${pointA.pointId}-${pointB.pointId}`,
24
+ description: `接边点 ${pointA.pointId} 与 ${pointB.pointId} 坐标偏差 ${distance.toFixed(6)} 米,超过容差 ${tolerance} 米`,
25
+ policyBasis: config.edgeMatching.policyBasis,
26
+ });
27
+ }
28
+ }
29
+ }
30
+ const edgeMatchingResult = {
31
+ mismatchedPairs,
32
+ policyBasis: config.edgeMatching.policyBasis,
33
+ };
34
+ return { edgeMatchingResult, checkResults };
35
+ }
36
+ calculateDistance(a, b) {
37
+ const dx = a.x - b.x;
38
+ const dy = a.y - b.y;
39
+ return Math.sqrt(dx * dx + dy * dy);
40
+ }
41
+ }
42
+ //# sourceMappingURL=edge-matching-checker.js.map
@@ -0,0 +1,50 @@
1
+ export class ErrorClassifier {
2
+ classify(checkResults, policyBasis) {
3
+ let classACount = 0;
4
+ let classBCount = 0;
5
+ let classCCount = 0;
6
+ let classDCount = 0;
7
+ for (const result of checkResults) {
8
+ switch (result.errorClass) {
9
+ case 'A':
10
+ classACount++;
11
+ break;
12
+ case 'B':
13
+ classBCount++;
14
+ break;
15
+ case 'C':
16
+ classCCount++;
17
+ break;
18
+ case 'D':
19
+ classDCount++;
20
+ break;
21
+ }
22
+ }
23
+ return {
24
+ classACount,
25
+ classBCount,
26
+ classCCount,
27
+ classDCount,
28
+ totalCount: classACount + classBCount + classCCount + classDCount,
29
+ policyBasis,
30
+ };
31
+ }
32
+ calculateProportions(stats) {
33
+ const total = stats.totalCount;
34
+ if (total === 0) {
35
+ return {
36
+ classAProportion: 0,
37
+ classBProportion: 0,
38
+ classCProportion: 0,
39
+ classDProportion: 0,
40
+ };
41
+ }
42
+ return {
43
+ classAProportion: Math.round((stats.classACount / total) * 10000) / 100,
44
+ classBProportion: Math.round((stats.classBCount / total) * 10000) / 100,
45
+ classCProportion: Math.round((stats.classCCount / total) * 10000) / 100,
46
+ classDProportion: Math.round((stats.classDCount / total) * 10000) / 100,
47
+ };
48
+ }
49
+ }
50
+ //# sourceMappingURL=error-classifier.js.map
@@ -0,0 +1,69 @@
1
+ export class FlowDirectionChecker {
2
+ check(dataset, config) {
3
+ const checkResults = [];
4
+ const invalidFlowSegments = [];
5
+ const pointElevationMap = new Map();
6
+ for (const point of dataset.points) {
7
+ pointElevationMap.set(point.pointId, point.elevation);
8
+ }
9
+ const allowedFlowDirections = new Set(config.flowDirectionEnum.allowedValues);
10
+ for (const segment of dataset.segments) {
11
+ if (segment.flowDirection === undefined)
12
+ continue;
13
+ if (!allowedFlowDirections.has(segment.flowDirection)) {
14
+ invalidFlowSegments.push({
15
+ segmentId: segment.segmentId,
16
+ description: `管段 ${segment.segmentId} 流向 ${segment.flowDirection} 不在合法枚举中`,
17
+ });
18
+ checkResults.push({
19
+ checkName: '排水流向检查',
20
+ errorClass: 'C',
21
+ objectId: segment.segmentId,
22
+ description: `管段 ${segment.segmentId} 流向 ${segment.flowDirection} 不在合法枚举中`,
23
+ policyBasis: config.flowDirectionEnum.policyBasis,
24
+ });
25
+ continue;
26
+ }
27
+ if (segment.flowDirection === '未知')
28
+ continue;
29
+ const startElevation = pointElevationMap.get(segment.startPointId);
30
+ const endElevation = pointElevationMap.get(segment.endPointId);
31
+ if (startElevation === undefined || endElevation === undefined)
32
+ continue;
33
+ const elevationDiff = startElevation - endElevation;
34
+ const epsilon = 1e-9;
35
+ if (segment.flowDirection === '顺流' && elevationDiff < -epsilon) {
36
+ invalidFlowSegments.push({
37
+ segmentId: segment.segmentId,
38
+ description: `管段 ${segment.segmentId} 流向为顺流但起点高程 ${startElevation} 低于终点高程 ${endElevation}`,
39
+ });
40
+ checkResults.push({
41
+ checkName: '排水流向检查',
42
+ errorClass: 'C',
43
+ objectId: segment.segmentId,
44
+ description: `管段 ${segment.segmentId} 流向为顺流但起点高程 ${startElevation} 低于终点高程 ${endElevation}`,
45
+ policyBasis: config.flowDirectionEnum.policyBasis,
46
+ });
47
+ }
48
+ else if (segment.flowDirection === '逆流' && elevationDiff > epsilon) {
49
+ invalidFlowSegments.push({
50
+ segmentId: segment.segmentId,
51
+ description: `管段 ${segment.segmentId} 流向为逆流但起点高程 ${startElevation} 高于终点高程 ${endElevation}`,
52
+ });
53
+ checkResults.push({
54
+ checkName: '排水流向检查',
55
+ errorClass: 'C',
56
+ objectId: segment.segmentId,
57
+ description: `管段 ${segment.segmentId} 流向为逆流但起点高程 ${startElevation} 高于终点高程 ${endElevation}`,
58
+ policyBasis: config.flowDirectionEnum.policyBasis,
59
+ });
60
+ }
61
+ }
62
+ const flowDirectionResult = {
63
+ invalidFlowSegments,
64
+ policyBasis: config.flowDirectionEnum.policyBasis,
65
+ };
66
+ return { flowDirectionResult, checkResults };
67
+ }
68
+ }
69
+ //# sourceMappingURL=flow-direction-checker.js.map
@@ -0,0 +1,26 @@
1
+ export class GrossErrorRateCalculator {
2
+ calculate(checkResults, totalPoints, config) {
3
+ const grossErrorPointIds = new Set();
4
+ for (const result of checkResults) {
5
+ if (result.errorClass === 'A') {
6
+ grossErrorPointIds.add(result.objectId);
7
+ }
8
+ }
9
+ const grossErrorPoints = grossErrorPointIds.size;
10
+ const threshold = config.grossErrorRate.thresholdRate;
11
+ let rate = 0;
12
+ if (totalPoints > 0) {
13
+ rate = grossErrorPoints / totalPoints;
14
+ }
15
+ const passed = rate <= threshold;
16
+ return {
17
+ totalPoints,
18
+ grossErrorPoints,
19
+ rate: Math.round(rate * 10000) / 10000,
20
+ threshold,
21
+ passed,
22
+ policyBasis: config.grossErrorRate.policyBasis,
23
+ };
24
+ }
25
+ }
26
+ //# sourceMappingURL=gross-error-rate-calculator.js.map