- 데모 v2 이후 개발 PC의 변경을 옮김 (이 저장소의 이름 변경·README 정리는 유지) - 서버 기본 DEM, DEM 등고선, 속성 테이블 범위 선택, WNTR 교차 검증 시험 포함 - 새 라이브러리: ezdxf(Python), maplibre-contour(npm) - 변경 내역: docs/SPipe_패치내역_도면출력_2026-11-06.txt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
276 lines
7.3 KiB
TypeScript
276 lines
7.3 KiB
TypeScript
import type { FeatureCollection } from 'geojson';
|
|
|
|
export interface NodeTimeSeries {
|
|
demand: number[];
|
|
head: number[];
|
|
pressure: number[];
|
|
quality: number[];
|
|
}
|
|
|
|
export interface LinkTimeSeries {
|
|
flow: number[];
|
|
velocity: number[];
|
|
headloss: number[];
|
|
quality: number[];
|
|
energy?: number[];
|
|
efficiency?: number[];
|
|
}
|
|
|
|
export interface NodeResult {
|
|
id: string;
|
|
type: number;
|
|
coordinates: { x: number; y: number } | null;
|
|
demand: number;
|
|
head: number;
|
|
pressure: number;
|
|
quality?: number;
|
|
timeSeries?: NodeTimeSeries;
|
|
}
|
|
|
|
export interface LinkResult {
|
|
id: string;
|
|
type: number;
|
|
fromNode: string;
|
|
toNode: string;
|
|
vertices: { x: number; y: number }[];
|
|
flow: number;
|
|
velocity: number;
|
|
headloss: number;
|
|
quality?: number;
|
|
energy?: number;
|
|
efficiency?: number;
|
|
totalKwh?: number;
|
|
peakKw?: number;
|
|
avgKw?: number;
|
|
utilization?: number;
|
|
timeSeries?: LinkTimeSeries;
|
|
}
|
|
|
|
export interface SimulationResult {
|
|
engine: { runtime: "native" | "wasm"; version: "2.3.5" };
|
|
timeSeconds: number;
|
|
timeSteps?: number[];
|
|
units: { flow: string; pressure: string };
|
|
nodes: Record<string, NodeResult>;
|
|
links: Record<string, LinkResult>;
|
|
reportText?: string;
|
|
qualityInfo?: QualityInfo;
|
|
energySummary?: PumpEnergySummary;
|
|
/** Warning codes (1-6) returned directly by EN_runH, independent of [REPORT] MESSAGES. */
|
|
engineWarnings?: { time: number; code: number }[];
|
|
/** [TIMES] REPORT START / REPORT TIMESTEP in seconds. timeSteps also holds
|
|
* intermediate event times (tank fills, controls); use reportingStepIndices
|
|
* for the periods EPANET itself reports. */
|
|
reportStart?: number;
|
|
reportStep?: number;
|
|
}
|
|
|
|
export interface PumpEnergyResult {
|
|
id: string;
|
|
fromNode: string;
|
|
toNode: string;
|
|
totalKwh: number;
|
|
peakKw: number;
|
|
avgKw: number;
|
|
avgEfficiency: number;
|
|
utilization: number;
|
|
}
|
|
|
|
export interface PumpEnergySummary {
|
|
pumps: Record<string, PumpEnergyResult>;
|
|
totalKwh: number;
|
|
peakKw: number;
|
|
}
|
|
|
|
export interface QualityInfo {
|
|
qualType: number;
|
|
typeName: 'NONE' | 'CHEMICAL' | 'AGE' | 'TRACE';
|
|
chemName: string;
|
|
chemUnits: string;
|
|
traceNode?: string;
|
|
status: 'none' | 'success' | 'failed';
|
|
errorMessage?: string;
|
|
}
|
|
|
|
export type ComparisonVariable = 'demand' | 'head' | 'pressure' | 'flow' | 'velocity' | 'headloss' | 'quality';
|
|
|
|
export interface ToleranceConfig {
|
|
absTol: number;
|
|
relTol: number;
|
|
}
|
|
|
|
export interface ToleranceViolation {
|
|
variable: ComparisonVariable;
|
|
id: string;
|
|
time: number;
|
|
diff: number;
|
|
tolerance: number;
|
|
}
|
|
|
|
export interface ComparisonResult {
|
|
passed: boolean;
|
|
maxDiffs: Record<ComparisonVariable, number>;
|
|
maxRelativeDiffs: Record<ComparisonVariable, number>;
|
|
maxSignificantRelativeDiffs: Record<ComparisonVariable, number>;
|
|
nearZeroCounts: Record<ComparisonVariable, number>;
|
|
toleranceViolations: ToleranceViolation[];
|
|
missingIds: string[];
|
|
}
|
|
|
|
export type SelectionTarget =
|
|
| { type: 'node'; id: string }
|
|
| { type: 'link'; id: string }
|
|
| {
|
|
type: 'gis-feature';
|
|
layerId: string;
|
|
featureId: string | number;
|
|
properties: Record<string, unknown>;
|
|
geometryType?: string;
|
|
}
|
|
| null;
|
|
|
|
export interface MultiSelectionState {
|
|
nodes: Set<string>;
|
|
links: Set<string>;
|
|
gisFeatures: Array<{ layerId: string; featureId: string | number }>;
|
|
}
|
|
|
|
export type EditMode = 'select' | 'add-node' | 'add-pipe';
|
|
|
|
/** Text shown next to a node / at a link midpoint (calibration values, analysis results ...). */
|
|
export interface MapAnnotation {
|
|
type: 'node' | 'link';
|
|
id: string;
|
|
text: string;
|
|
color?: string;
|
|
}
|
|
|
|
/** DEM 등고선 on the map (maplibre-contour over the API's terrain tiles). */
|
|
export interface DemContours {
|
|
demId: string;
|
|
/** Minor contour interval (m); every 5th is a labelled major line. */
|
|
interval: number;
|
|
/** Highest useful tile zoom for this DEM's resolution. */
|
|
maxzoom: number;
|
|
}
|
|
|
|
/** 3D 보기: tilted map, optional DEM terrain and node columns. */
|
|
export interface View3D {
|
|
enabled: boolean;
|
|
/** DEM id for terrain (server terrain tiles); none = flat ground. */
|
|
demId?: string;
|
|
exaggeration: number;
|
|
/** Node columns: height from this display value (m). */
|
|
columns: 'none' | 'head' | 'pressure' | 'elevation';
|
|
columnScale: number;
|
|
}
|
|
|
|
/** Image draped on the map by its four corners (DEM shading, aerial photo, scanned drawing). */
|
|
export interface RasterOverlay {
|
|
id: string;
|
|
name: string;
|
|
url: string;
|
|
/** [lng, lat] of top-left, top-right, bottom-right, bottom-left. */
|
|
corners: [number, number][];
|
|
opacity: number;
|
|
visible: boolean;
|
|
}
|
|
|
|
/** Right dock tab. */
|
|
export type RightTab = 'inspector' | 'results' | 'verification' | 'analysis';
|
|
export type DisplayMode =
|
|
| 'pressure'
|
|
| 'flow'
|
|
| 'head'
|
|
| 'velocity'
|
|
| 'headloss'
|
|
| 'elevation'
|
|
| 'diff-pressure'
|
|
| 'diff-flow'
|
|
| 'quality';
|
|
|
|
export interface Scenario {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
inpStr: string;
|
|
result: SimulationResult | null;
|
|
createdAt: string;
|
|
}
|
|
|
|
|
|
export type BasemapType =
|
|
| 'blank'
|
|
| 'osm'
|
|
| 'vworld'
|
|
| 'vworld-white'
|
|
| 'vworld-midnight'
|
|
| 'vworld-satellite'
|
|
| 'vworld-satellite-hybrid';
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
User GIS Reference Layers
|
|
--------------------------------------------------------------------------- */
|
|
export interface UserGisLayer {
|
|
id: string;
|
|
name: string;
|
|
fileName: string;
|
|
featureCollection: FeatureCollection;
|
|
featureCount: number;
|
|
geomTypes: string[];
|
|
estimatedCrs: string;
|
|
visible: boolean;
|
|
opacity: number; // 0.0 ~ 1.0
|
|
color: string;
|
|
createdAt: string;
|
|
/** CRS the source coordinates were read as (EPSG code / proj4); lets the
|
|
* layer be reassigned when that guess was wrong. Absent = WGS84 / unknown. */
|
|
sourceCrs?: string;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Layer Visibility State
|
|
--------------------------------------------------------------------------- */
|
|
export interface LayerVisibilityState {
|
|
// 관망 모델 요소별
|
|
nodes: boolean;
|
|
pipes: boolean;
|
|
pumps: boolean;
|
|
valves: boolean;
|
|
tanksReservoirs: boolean;
|
|
// 레이어별 투명도 (0.0 ~ 1.0)
|
|
networkOpacity: {
|
|
nodes: number;
|
|
pipes: number;
|
|
pumps: number;
|
|
valves: number;
|
|
tanksReservoirs: number;
|
|
};
|
|
// 결과 표시
|
|
results: {
|
|
visible: boolean;
|
|
opacity: number;
|
|
};
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Map Context Menu Event
|
|
--------------------------------------------------------------------------- */
|
|
export type ContextMenuTarget =
|
|
| { type: 'canvas'; lngLat: [number, number]; modelCoords: [number, number] }
|
|
| { type: 'node'; id: string; lngLat: [number, number]; modelCoords?: [number, number] }
|
|
| { type: 'link'; id: string; lngLat: [number, number] }
|
|
| {
|
|
type: 'gis-feature';
|
|
layerId: string;
|
|
featureId: string | number;
|
|
properties: Record<string, unknown>;
|
|
lngLat: [number, number];
|
|
};
|
|
|
|
export interface MapContextMenuEvent {
|
|
x: number;
|
|
y: number;
|
|
target: ContextMenuTarget;
|
|
}
|