Spaces:
Paused
Paused
Deploy full studio app to HF
Browse files- .dockerignore +6 -0
- .gitattributes +1 -0
- Dockerfile +14 -3
- lib/приложение 6 Альбом и матрица мнемосхем Общий внедрение и проектирование 1.9 (1).xlsm +3 -0
- mnemo-studio-tool/web/Statics.xml +2407 -0
- mnemo-studio-tool/web/Widget.json +0 -0
- web-new/src/App.css +45 -2
- web-new/src/App.jsx +207 -70
- web-new/src/api.js +42 -6
- web-new/src/components/ElementLibraryPanel.css +169 -0
- web-new/src/components/ElementLibraryPanel.jsx +217 -0
- web-new/src/components/Inspector.jsx +109 -14
- web-new/src/components/SvgWorkspace.jsx +826 -116
- web-new/src/constants.js +28 -16
- web-new/src/hooks/useAnnotationTools.js +44 -4
- web-new/src/store/actions.js +1 -0
- web-new/src/store/reducer.js +35 -1
- web-new/src/utils/xmlBuilder.js +59 -0
.dockerignore
CHANGED
|
@@ -2,6 +2,12 @@ web-new/node_modules
|
|
| 2 |
web-new/.vite
|
| 3 |
web-new/dist
|
| 4 |
mnemo-studio-tool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
__pycache__
|
| 6 |
*.pyc
|
| 7 |
.pytest_cache
|
|
|
|
| 2 |
web-new/.vite
|
| 3 |
web-new/dist
|
| 4 |
mnemo-studio-tool
|
| 5 |
+
!mnemo-studio-tool/
|
| 6 |
+
mnemo-studio-tool/*
|
| 7 |
+
!mnemo-studio-tool/web/
|
| 8 |
+
mnemo-studio-tool/web/*
|
| 9 |
+
!mnemo-studio-tool/web/Widget.json
|
| 10 |
+
!mnemo-studio-tool/web/Statics.xml
|
| 11 |
__pycache__
|
| 12 |
*.pyc
|
| 13 |
.pytest_cache
|
.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
lib/*.xlsm filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
FROM python:3.10-slim
|
| 2 |
|
| 3 |
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 4 |
PYTHONUNBUFFERED=1 \
|
| 5 |
PORT=7860 \
|
| 6 |
-
FRONTEND_MODE=
|
|
|
|
| 7 |
MNEMO_DETECTOR_MODE=colab-pipeline \
|
|
|
|
| 8 |
MNEMO_SENSOR_OCR_ENGINE=easyocr \
|
| 9 |
MNEMO_PADDLE_DEVICE=cpu \
|
| 10 |
MNEMO_EASYOCR_DEVICE=cpu
|
| 11 |
|
| 12 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 13 |
gcc g++ build-essential \
|
| 14 |
-
libglib2.0-0 libgl1 \
|
| 15 |
&& rm -rf /var/lib/apt/lists/*
|
| 16 |
|
| 17 |
WORKDIR /app
|
|
@@ -21,7 +31,8 @@ COPY requirements.txt .
|
|
| 21 |
RUN pip install --upgrade pip && pip install -r requirements.txt
|
| 22 |
|
| 23 |
COPY . .
|
|
|
|
| 24 |
|
| 25 |
EXPOSE 7860
|
| 26 |
|
| 27 |
-
CMD ["python", "app.py", "--frontend-mode", "
|
|
|
|
| 1 |
+
FROM node:20-bookworm-slim AS web-builder
|
| 2 |
+
|
| 3 |
+
WORKDIR /src/web-new
|
| 4 |
+
COPY web-new/package*.json ./
|
| 5 |
+
RUN npm ci
|
| 6 |
+
COPY web-new/ ./
|
| 7 |
+
RUN npm run build
|
| 8 |
+
|
| 9 |
FROM python:3.10-slim
|
| 10 |
|
| 11 |
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 12 |
PYTHONUNBUFFERED=1 \
|
| 13 |
PORT=7860 \
|
| 14 |
+
FRONTEND_MODE=studio \
|
| 15 |
+
WEB_ROOT=/app/web \
|
| 16 |
MNEMO_DETECTOR_MODE=colab-pipeline \
|
| 17 |
+
MNEMO_ANALYZE_USE_EXCEL=1 \
|
| 18 |
MNEMO_SENSOR_OCR_ENGINE=easyocr \
|
| 19 |
MNEMO_PADDLE_DEVICE=cpu \
|
| 20 |
MNEMO_EASYOCR_DEVICE=cpu
|
| 21 |
|
| 22 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 23 |
gcc g++ build-essential \
|
| 24 |
+
libglib2.0-0 libgl1 libgomp1 \
|
| 25 |
&& rm -rf /var/lib/apt/lists/*
|
| 26 |
|
| 27 |
WORKDIR /app
|
|
|
|
| 31 |
RUN pip install --upgrade pip && pip install -r requirements.txt
|
| 32 |
|
| 33 |
COPY . .
|
| 34 |
+
COPY --from=web-builder /src/web /app/web
|
| 35 |
|
| 36 |
EXPOSE 7860
|
| 37 |
|
| 38 |
+
CMD ["python", "app.py", "--frontend-mode", "studio"]
|
lib/приложение 6 Альбом и матрица мнемосхем Общий внедрение и проектирование 1.9 (1).xlsm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:904e6238ea08384af76b91883e86d554768e5a070b933a9b6b07f3d0e58761c5
|
| 3 |
+
size 94933543
|
mnemo-studio-tool/web/Statics.xml
ADDED
|
@@ -0,0 +1,2407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<shapes name="Rusal"><shape h="32.0" w="40.0" aspect="variable" strokewidth="inherit" name="adjustable_valve_horizontal" displayName="adjustable_valve_horizontal"><foreground><path><move x="20.0" y="19.5" /><line x="20.0" y="9.06" /></path><stroke /><path><move x="0.0" y="8.0" /><line x="20.0" y="20.0" /><line x="0.0" y="32.0" /><close /><move x="40.0" y="8.0" /><line x="20.0" y="20.0" /><line x="40.0" y="32.0" /><close /></path><fillstroke /><stroke /><path><move x="7.940000000000001" y="9.059999999999999" /><curve x1="7.940000000000001" y1="0.05999999999999872" x2="20.0" y2="0.05999999999999961" x3="20.0" y3="0.05999999999999961" /><curve x1="32.06" y1="0.0600000000000005" x2="32.06" y2="9.06" x3="32.06" y3="9.06" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="40.0" w="32.0" aspect="variable" strokewidth="inherit" name="adjustable_valve_vertical" displayName="adjustable_valve_vertical"><foreground><path><move x="12.0" y="20.0" /><line x="23.0" y="20.0" /></path><stroke /><path><move x="24.0" y="0.0" /><line x="12.0" y="20.0" /><line x="-1.7763568394002505e-15" y="0.0" /><close /><move x="24.0" y="40.0" /><line x="12.0" y="20.0" /><line x="1.7763568394002505e-15" y="40.0" /><close /></path><fillstroke /><stroke /><path><move x="23.0" y="8.0" /><curve x1="32.0" y1="8.0" x2="32.0" y2="20.06" x3="32.0" y3="20.06" /><curve x1="32.0" y1="32.12" x2="23.0" y2="32.12" x3="23.0" y3="32.12" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="62.0" w="86.0" aspect="variable" strokewidth="inherit" name="aerial_dryer" displayName="aerial_dryer"><foreground><rect x="0" y="16" w="78" h="46" /><fillstroke /><stroke /><rect x="4" y="0" w="17" h="16" /><fillstroke /><stroke /><rect x="78" y="28.5" w="8" h="21" /><fillstroke /><stroke /></foreground></shape><shape h="159.0" w="32.0" aspect="variable" strokewidth="inherit" name="autoclave" displayName="autoclave"><foreground><ellipse x="0.0" y="0.0" w="32.0" h="29.0" /><fillstroke /><stroke /><ellipse x="0.0" y="130.0" w="32.0" h="29.0" /><fillstroke /><stroke /><rect x="0" y="19" w="32" h="121" /><fillstroke /><stroke /><rect x="0" y="14" w="32" h="5" /><fillstroke /><stroke /><rect x="0" y="140" w="32" h="5" /><fillstroke /><stroke /></foreground></shape><shape h="43.0" w="56.0" aspect="variable" strokewidth="inherit" name="batcher" displayName="batcher"><foreground><rect x="0.06" y="0" w="40.65" h="8.85" /><fillstroke /><stroke /><path><move x="40.72" y="8.850000000000003" /><line x="33.26" y="35.41" /><line x="7.520000000000001" y="35.41" /><line x="0.060000000000002274" y="8.85" /><close /></path><fillstroke /><stroke /><path><move x="55.18" y="38.33" /><line x="55.18" y="42.6" /><line x="3.7900000000000027" y="42.60000000000001" /><line x="3.7900000000000027" y="33.330000000000005" /><line x="50.18" y="33.33" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="42.0" w="63.0" aspect="variable" strokewidth="inherit" name="block" displayName="block"><foreground><path><move x="63.5" y="-3.552713678800501e-15" /><line x="32.0" y="42.0" /><line x="0.5" y="3.552713678800501e-15" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="112.0" w="58.0" aspect="variable" strokewidth="inherit" name="boiler" displayName="boiler">
|
| 2 |
+
<foreground>
|
| 3 |
+
<roundrect arcsize="10" x="0" y="0" w="50.67" h="111" />
|
| 4 |
+
<fillstroke />
|
| 5 |
+
<stroke />
|
| 6 |
+
<rect x="50.67" y="19.59" w="6.33" h="11.43" />
|
| 7 |
+
<fillstroke />
|
| 8 |
+
<stroke />
|
| 9 |
+
<path>
|
| 10 |
+
<move x="5.55" y="8.16" />
|
| 11 |
+
<curve x1="0.0" y1="8.16" x2="0.0" x3="0.0" y2="8.16" y3="8.16" />
|
| 12 |
+
</path>
|
| 13 |
+
<fillstroke />
|
| 14 |
+
<stroke />
|
| 15 |
+
<path>
|
| 16 |
+
<move x="45.11" y="8.17" />
|
| 17 |
+
<curve x1="50.67" y1="8.17" x2="50.67" x3="50.67" y2="8.17" y3="8.17" />
|
| 18 |
+
</path>
|
| 19 |
+
<fillstroke />
|
| 20 |
+
<stroke />
|
| 21 |
+
<path>
|
| 22 |
+
<move x="5.55" y="100.39" />
|
| 23 |
+
<curve x1="10" y1="110.39" x2="13.44" x3="13.44" y2="100.39" y3="100.39" />
|
| 24 |
+
</path>
|
| 25 |
+
<fillstroke />
|
| 26 |
+
<stroke />
|
| 27 |
+
<path>
|
| 28 |
+
<move x="21.37" y="100.39" />
|
| 29 |
+
<curve x1="41.16" y1="110.39" x2="45.11" x3="45.11" y2="100.39" y3="100.39" />
|
| 30 |
+
</path>
|
| 31 |
+
<path>
|
| 32 |
+
<move x="21.37" y="100.39" />
|
| 33 |
+
<curve x1="25.33" y1="110.39" x2="29.29" x3="29.29" y2="100.39" y3="100.39" />
|
| 34 |
+
</path>
|
| 35 |
+
<fillstroke />
|
| 36 |
+
<stroke />
|
| 37 |
+
<path>
|
| 38 |
+
<move x="37.211" y="100.39" />
|
| 39 |
+
<curve x1="41.16" y1="110.39" x2="45.11" x3="45.11" y2="100.39" y3="100.39" />
|
| 40 |
+
</path>
|
| 41 |
+
<fillstroke />
|
| 42 |
+
<stroke />
|
| 43 |
+
<path>
|
| 44 |
+
<move x="29.29" y="16.21" />
|
| 45 |
+
<curve x1="33.25" y1="6.21" x2="37.211" x3="37.211" y2="16.21" y3="16.21" />
|
| 46 |
+
</path>
|
| 47 |
+
<fillstroke />
|
| 48 |
+
<stroke />
|
| 49 |
+
<path>
|
| 50 |
+
<move x="13.46" y="16.21" />
|
| 51 |
+
<curve x1="17.42" y1="6.21" x2="21.37" x3="21.37" y2="16.21" y3="16.21" />
|
| 52 |
+
</path>
|
| 53 |
+
<fillstroke />
|
| 54 |
+
<stroke />
|
| 55 |
+
<path>
|
| 56 |
+
<move x="21.38" y="100.39" />
|
| 57 |
+
<curve x1="21.38" y1="16.32" x2="21.38" x3="21.38" y2="16.32" y3="16.32" />
|
| 58 |
+
</path>
|
| 59 |
+
<fillstroke />
|
| 60 |
+
<stroke />
|
| 61 |
+
<path>
|
| 62 |
+
<move x="29.29" y="100.39" />
|
| 63 |
+
<curve x1="29.29" y1="16.32" x2="29.29" x3="29.29" y2="16.32" y3="16.32" />
|
| 64 |
+
</path>
|
| 65 |
+
<fillstroke />
|
| 66 |
+
<stroke />
|
| 67 |
+
<path>
|
| 68 |
+
<move x="37.21" y="100.39" />
|
| 69 |
+
<curve x1="37.21" y1="16.32" x2="37.21" x3="37.21" y2="16.32" y3="16.32" />
|
| 70 |
+
</path>
|
| 71 |
+
<fillstroke />
|
| 72 |
+
<stroke />
|
| 73 |
+
<path>
|
| 74 |
+
<move x="13.46" y="100.39" />
|
| 75 |
+
<curve x1="13.46" y1="16.32" x2="13.46" x3="13.46" y2="16.32" y3="16.32" />
|
| 76 |
+
</path>
|
| 77 |
+
<fillstroke />
|
| 78 |
+
<stroke />
|
| 79 |
+
<path>
|
| 80 |
+
<move x="0.9" y="4.08" />
|
| 81 |
+
<line x="49.9" y="4.08" />
|
| 82 |
+
</path>
|
| 83 |
+
<fillstroke />
|
| 84 |
+
<stroke />
|
| 85 |
+
<path>
|
| 86 |
+
<move x="5.53" y="100.58" />
|
| 87 |
+
<curve x1="5.52" y1="8.05" x2="5.52" x3="5.52" y2="8.05" y3="8.05" />
|
| 88 |
+
</path>
|
| 89 |
+
<fillstroke />
|
| 90 |
+
<stroke />
|
| 91 |
+
<path>
|
| 92 |
+
<move x="45.11" y="8.05" />
|
| 93 |
+
<curve x1="45.11" y1="100.28" x2="45.11" x3="45.11" y2="100.28" y3="100.28" />
|
| 94 |
+
</path>
|
| 95 |
+
<fillstroke />
|
| 96 |
+
<stroke />
|
| 97 |
+
<path>
|
| 98 |
+
<move x="21.36" y="100.28" />
|
| 99 |
+
<curve x1="21.36" y1="16.21" x2="21.36" x3="21.36" y2="16.21" y3="16.21" />
|
| 100 |
+
</path>
|
| 101 |
+
<fillstroke />
|
| 102 |
+
<stroke />
|
| 103 |
+
<path>
|
| 104 |
+
<move x="29.27" y="100.28" />
|
| 105 |
+
<curve x1="29.27" y1="16.21" x2="29.27" x3="29.27" y2="16.21" y3="16.21" />
|
| 106 |
+
</path>
|
| 107 |
+
<fillstroke />
|
| 108 |
+
<stroke />
|
| 109 |
+
<path>
|
| 110 |
+
<move x="37.19" y="100.28" />
|
| 111 |
+
<curve x1="37.19" y1="16.21" x2="37.19" x3="37.19" y2="16.21" y3="16.21" />
|
| 112 |
+
</path>
|
| 113 |
+
<fillstroke />
|
| 114 |
+
<stroke />
|
| 115 |
+
<path>
|
| 116 |
+
<move x="13.44" y="100.28" />
|
| 117 |
+
<curve x1="13.44" y1="16.21" x2="13.44" x3="13.44" y2="16.21" y3="16.21" />
|
| 118 |
+
</path>
|
| 119 |
+
<fillstroke />
|
| 120 |
+
<stroke />
|
| 121 |
+
</foreground>
|
| 122 |
+
</shape><shape h="85.0" w="50.0" aspect="variable" strokewidth="inherit" name="bunker" displayName="bunker"><foreground><rect x="0" y="0" w="50" h="72" /><fillstroke /><stroke /><path><move x="37.0" y="85.0" /><line x="13.0" y="85.0" /><line x="0.0" y="74.6" /><line x="0.0" y="72.0" /><line x="50.0" y="72.0" /><line x="50.0" y="74.6" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="122.0" w="88.0" aspect="variable" strokewidth="inherit" name="bypass_switch" displayName="bypass_switch">
|
| 123 |
+
<foreground>
|
| 124 |
+
<ellipse x="54.00000000000001" y="59.309999999999995" w="24.8" h="24.8" />
|
| 125 |
+
<fillstroke />
|
| 126 |
+
<stroke />
|
| 127 |
+
<path>
|
| 128 |
+
<move x="66.4" y="59.31" />
|
| 129 |
+
<line x="66.43" y="37.29" />
|
| 130 |
+
<line x="29.0" y="37.31" />
|
| 131 |
+
</path>
|
| 132 |
+
<stroke />
|
| 133 |
+
<ellipse x="44.0" y="74.30999999999999" w="24.8" h="24.8" />
|
| 134 |
+
<fillstroke />
|
| 135 |
+
<stroke />
|
| 136 |
+
<ellipse x="63.00000000000001" y="74.30999999999999" w="24.8" h="24.8" />
|
| 137 |
+
<fillstroke />
|
| 138 |
+
<stroke />
|
| 139 |
+
<path>
|
| 140 |
+
<move x="18.11" y="0.0" />
|
| 141 |
+
<line x="18.14" y="118.29" />
|
| 142 |
+
</path>
|
| 143 |
+
<fillstroke />
|
| 144 |
+
<stroke />
|
| 145 |
+
<path>
|
| 146 |
+
<move x="18.04" y="99.31" />
|
| 147 |
+
<line x="0.0" y="99.29" />
|
| 148 |
+
<line x="0.0" y="120.29" />
|
| 149 |
+
</path>
|
| 150 |
+
<stroke />
|
| 151 |
+
<rect x="7" y="27.81" w="22" h="19" />
|
| 152 |
+
<fillstroke />
|
| 153 |
+
<stroke />
|
| 154 |
+
<ellipse x="44.0" y="74.30999999999999" w="24.8" h="24.8" />
|
| 155 |
+
<stroke />
|
| 156 |
+
<ellipse x="54.00000000000001" y="59.309999999999995" w="24.8" h="24.8" />
|
| 157 |
+
<stroke />
|
| 158 |
+
</foreground>
|
| 159 |
+
</shape><shape h="55.0" w="98.0" aspect="variable" strokewidth="inherit" name="capacitor" displayName="capacitor">
|
| 160 |
+
<foreground>
|
| 161 |
+
<rect x="31" y="35" w="36" h="20" />
|
| 162 |
+
<fillstroke />
|
| 163 |
+
<stroke />
|
| 164 |
+
<ellipse x="19.0" y="0.0" w="60.0" h="45.0" />
|
| 165 |
+
<fillstroke />
|
| 166 |
+
<stroke />
|
| 167 |
+
<path>
|
| 168 |
+
<move x="0.0" y="32.11" />
|
| 169 |
+
<line x="37.0" y="32.0" />
|
| 170 |
+
<line x="31.0" y="23.0" />
|
| 171 |
+
<line x="37.0" y="14.0" />
|
| 172 |
+
<line x="0.0" y="14.0" />
|
| 173 |
+
</path>
|
| 174 |
+
<stroke />
|
| 175 |
+
<path>
|
| 176 |
+
<move x="96.24" y="32.0" />
|
| 177 |
+
<line x="60.0" y="32.0" />
|
| 178 |
+
<line x="68.0" y="23.0" />
|
| 179 |
+
<line x="60.0" y="14.0" />
|
| 180 |
+
<line x="96.24" y="14.12" />
|
| 181 |
+
</path>
|
| 182 |
+
<stroke />
|
| 183 |
+
</foreground>
|
| 184 |
+
</shape><shape h="146.0" w="64.0" aspect="variable" strokewidth="inherit" name="carbonator" displayName="carbonator"><foreground><rect x="0" y="0" w="64" h="73" /><fillstroke /><stroke /><path><move x="64.0" y="73.0" /><line x="41.49999999999999" y="146.0" /><line x="22.499999999999993" y="146.0" /><line x="3.552713678800501e-15" y="73.0" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="33.0" w="96.0" aspect="variable" strokewidth="inherit" name="centrifuge" displayName="centrifuge"><foreground><rect x="83" y="24" w="12" h="8" /><fillstroke /><stroke /><roundrect arcsize="1.82" x="24" y="0" w="71" h="26" /><fillstroke /><stroke /><rect x="6" y="10" w="18" h="6" /><fillstroke /><stroke /><rect x="0" y="16" w="24" h="16" /><fillstroke /><stroke /></foreground></shape><shape h="29.0" w="29.0" aspect="variable" strokewidth="inherit" name="chamber_pump" displayName="chamber_pump"><foreground><rect x="0" y="7.17" w="28" h="17" /><fillstroke /><stroke /><path><move x="0.0" y="7.17" /><line x="3.61" y="2.04" /><line x="24.27" y="2.04" /><line x="27.88" y="7.17" /><close /></path><fillstroke /><stroke /><path><move x="27.89" y="24.17" /><line x="23.28" y="28.769999999999996" /><line x="4.73" y="28.769999999999996" /><line x="0.120000000000001" y="24.169999999999995" /><close /></path><fillstroke /><stroke /><rect x="8.94" y="-0.23" w="9.53" h="2.27" /><fillstroke /><stroke /></foreground></shape><shape h="158.0" w="80.0" aspect="fixed" strokewidth="inherit" name="classifier" displayName="classifier">
|
| 185 |
+
<foreground>
|
| 186 |
+
<path>
|
| 187 |
+
<move x="64.35284264360266" y="27.040235488817537" />
|
| 188 |
+
<line x="69.30170248858624" y="37.65309967501671" />
|
| 189 |
+
<line x="49.36293117377994" y="46.9507014333121" />
|
| 190 |
+
<line x="44.414071328796354" y="36.33783724711293" />
|
| 191 |
+
<close />
|
| 192 |
+
</path>
|
| 193 |
+
<fillstroke />
|
| 194 |
+
<stroke />
|
| 195 |
+
<rect x="27" y="104" w="25" h="53" />
|
| 196 |
+
<fillstroke />
|
| 197 |
+
<stroke />
|
| 198 |
+
<roundrect arcsize="35" x="3" y="42" w="74" h="7" />
|
| 199 |
+
<fillstroke />
|
| 200 |
+
<stroke />
|
| 201 |
+
<roundrect arcsize="35" x="0" y="47" w="79" h="14" />
|
| 202 |
+
<fillstroke />
|
| 203 |
+
<stroke />
|
| 204 |
+
<path>
|
| 205 |
+
<move x="79.0" y="57.0" />
|
| 206 |
+
<line x="60.25" y="104.0" />
|
| 207 |
+
<line x="18.749999999999996" y="104.0" />
|
| 208 |
+
<line x="0.0" y="57.0" />
|
| 209 |
+
<close />
|
| 210 |
+
</path>
|
| 211 |
+
<fillstroke />
|
| 212 |
+
<stroke />
|
| 213 |
+
<path>
|
| 214 |
+
<move x="58.000000000000014" y="42.0" />
|
| 215 |
+
<line x="54.000000000000014" y="31.0" />
|
| 216 |
+
<line x="26.000000000000018" y="31.0" />
|
| 217 |
+
<line x="22.000000000000018" y="42.0" />
|
| 218 |
+
<close />
|
| 219 |
+
</path>
|
| 220 |
+
<fillstroke />
|
| 221 |
+
<stroke />
|
| 222 |
+
<rect x="29" y="18" w="22" h="13" />
|
| 223 |
+
<fillstroke />
|
| 224 |
+
<stroke />
|
| 225 |
+
<rect x="35" y="0" w="10" h="18" />
|
| 226 |
+
<fillstroke />
|
| 227 |
+
<stroke />
|
| 228 |
+
|
| 229 |
+
<path>
|
| 230 |
+
<move x="33.0" y="142.0" />
|
| 231 |
+
<line x="19.067445532594228" y="156.02379471869827" />
|
| 232 |
+
<line x="12.569134213489859" y="149.5254833995939" />
|
| 233 |
+
<line x="20" y="142.0" />
|
| 234 |
+
<line x="20" y="104.0" />
|
| 235 |
+
<line x="59.0" y="104.0" />
|
| 236 |
+
<line x="59.0" y="116.0" />
|
| 237 |
+
<close />
|
| 238 |
+
</path>
|
| 239 |
+
<fillstroke />
|
| 240 |
+
<stroke />
|
| 241 |
+
|
| 242 |
+
</foreground>
|
| 243 |
+
</shape><shape h="61.0" w="231.0" aspect="variable" strokewidth="inherit" name="CoKneader_Continuous" displayName="CoKneader_Continuous"><foreground><rect x="73.23" y="13.22" w="107.26" h="33.56" /><fillstroke /><stroke /><rect x="180.49" y="18.81" w="17.53" h="22.37" /><fillstroke /><stroke /><rect x="198.03" y="26.44" w="31.97" h="7.12" /><fillstroke /><stroke /><rect x="212.47" y="20.91" w="11.35" h="36.04" /><fillstroke /><stroke /><rect x="141.3" y="36.61" w="10.31" h="20.34" /><fillstroke /><stroke /><rect x="89.73" y="36.61" w="10.31" h="20.34" /><fillstroke /><stroke /><path><move x="62.98999999999999" y="0.16000000000000725" /><line x="73.16" y="8.910000000000007" /><line x="73.16" y="50.71000000000001" /><line x="62.989999999999995" y="59.46000000000001" /><close /></path><fillstroke /><stroke /><path><move x="25.459999999999994" y="59.65" /><line x="15.8" y="50.9" /><line x="15.8" y="9.099999999999998" /><line x="25.46" y="0.34999999999999787" /><close /></path><fillstroke /><stroke /><rect x="25.78" y="0" w="37.13" h="60" /><fillstroke /><stroke /><rect x="9.28" y="26.25" w="6.19" h="7.12" /><fillstroke /><stroke /><rect x="0" y="15.25" w="9.28" h="28.47" /><fillstroke /><stroke /><rect x="3.09" y="15.25" w="3.09" h="28.47" /><fillstroke /><stroke /></foreground></shape><shape h="47.0" w="66.0" aspect="variable" strokewidth="inherit" name="compressor" displayName="compressor"><foreground><path><move x="65.5" y="46.5" /><line x="0.5" y="39.37" /><line x="0.5" y="7.619999999999996" /><line x="65.5" y="0.5000000000000036" /><close /></path><fillstroke /><stroke /><path><move x="65.5" y="0.5" /><line x="65.5" y="46.49999999999999" /><line x="62.15" y="46.49999999999999" /><line x="62.15" y="0.5" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="25.0" w="266.0" aspect="variable" strokewidth="inherit" name="conveyor" displayName="conveyor"><foreground><rect x="12.22" y="0" w="238.84" h="25" /><fillstroke /><stroke /><ellipse x="0.0" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /><ellipse x="240.77" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /></foreground></shape><shape h="25.0" w="703.0" aspect="variable" strokewidth="inherit" name="conveyor_large" displayName="conveyor_large"><foreground><rect x="12" y="0" w="678" h="25" /><fillstroke /><stroke /><ellipse x="0.0" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /><ellipse x="677.0" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /></foreground></shape><shape h="25.0" w="121.0" aspect="variable" strokewidth="inherit" name="conveyor_small" displayName="conveyor_small"><foreground><rect x="13" y="0" w="95" h="25" /><fillstroke /><stroke /><ellipse x="0.0" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /><ellipse x="95.0" y="0.0" w="25.0" h="25.0" /><fillstroke /><stroke /></foreground></shape><shape h="97.0" w="88.0" aspect="variable" strokewidth="inherit" name="cooling_tower" displayName="cooling_tower"><foreground><path><move x="0.0" y="80.48" /><line x="17.6" y="0.0" /><line x="70.4" y="0.0" /><line x="88.0" y="80.48" /><close /></path><fillstroke /><stroke /><rect x="0" y="80.48" w="88" h="15.52" /><fillstroke /><stroke /><path><move x="74.4" y="17.06" /><line x="14.4" y="16.98" /></path><fillstroke /><stroke /><path><move x="43.74" y="80.64" /><line x="43.74" y="0.16" /></path><fillstroke /><stroke /><path><move x="69.04" y="80.48" /><line x="56.55" y="0.32" /></path><fillstroke /><stroke /><path><move x="19.98" y="80.6" /><line x="32.39" y="0.0" /></path><fillstroke /><stroke /><path><move x="77.4" y="32.0" /><line x="10.78" y="32.16" /></path><fillstroke /><stroke /><path><move x="81.4" y="47.73" /><line x="6.82" y="47.68" /></path><fillstroke /><stroke /><path><move x="84.4" y="63.24" /><line x="3.4" y="63.26" /></path><fillstroke /><stroke /></foreground></shape><shape h="73.0" w="73.0" aspect="variable" strokewidth="inherit" name="cooling_tower_section" displayName="cooling_tower_section"><foreground><rect x="0" y="0" w="72" h="72" /><fillstroke /><stroke /><ellipse x="3.1999999999999957" y="3.1999999999999957" w="65.60000000000001" h="65.60000000000001" /><fillstroke /><stroke /><path><move x="21.199999999999996" y="35.2" /><line x="36.0" y="4.0" /><line x="50.8" y="35.2" /><close /></path><fillstroke /><stroke /><path><move x="50.8" y="36.4" /><line x="36.0" y="67.6" /><line x="21.200000000000003" y="36.4" /><close /></path><fillstroke /><stroke /><path><move x="35.2" y="50.800000000000004" /><line x="4.0" y="36.0" /><line x="35.2" y="21.200000000000003" /><close /></path><fillstroke /><stroke /><path><move x="36.8" y="21.2" /><line x="68.0" y="36.0" /><line x="36.8" y="50.8" /><close /></path><fillstroke /><stroke /><ellipse x="22.4" y="22.4" w="27.200000000000003" h="27.200000000000003" /><fillstroke /><stroke /></foreground></shape><shape h="164.0" w="70.0" aspect="variable" strokewidth="inherit" name="correction_pool" displayName="correction_pool">
|
| 244 |
+
<foreground>
|
| 245 |
+
|
| 246 |
+
<path>
|
| 247 |
+
<move x="69.5" y="17.0" />
|
| 248 |
+
<line x="69.5" y="113.0" />
|
| 249 |
+
<line x="69.5" y="128.0" />
|
| 250 |
+
<line x="34.75" y="164.0" />
|
| 251 |
+
<line x="0.0" y="128.0" />
|
| 252 |
+
<line x="0.0" y="17.0" />
|
| 253 |
+
<curve x1="0" y1="0" x2="17" x3="17" y2="0" y3="0" />
|
| 254 |
+
<move x="17.0" y="0.0" />
|
| 255 |
+
<line x="52.5" y="0.0" />
|
| 256 |
+
<curve x1="69.5" y1="0" x2="69.5" x3="69.5" y2="17" y3="17" />
|
| 257 |
+
</path>
|
| 258 |
+
<fillstroke />
|
| 259 |
+
|
| 260 |
+
</foreground>
|
| 261 |
+
</shape><shape h="131.0" w="90.0" aspect="variable" strokewidth="inherit" name="countercurrent_evaporator" displayName="countercurrent_evaporator">
|
| 262 |
+
<foreground>
|
| 263 |
+
<roundrect arcsize="8" x="21.51" y="0" w="51" h="121" />
|
| 264 |
+
<fillstroke />
|
| 265 |
+
<stroke />
|
| 266 |
+
<path>
|
| 267 |
+
<move x="67.00999999999999" y="121.24000000000001" />
|
| 268 |
+
<line x="47.01" y="130.99" />
|
| 269 |
+
<line x="27.009999999999998" y="121.24000000000001" />
|
| 270 |
+
<close />
|
| 271 |
+
</path>
|
| 272 |
+
<fillstroke />
|
| 273 |
+
<stroke />
|
| 274 |
+
<path>
|
| 275 |
+
<move x="21.5" y="42.0" />
|
| 276 |
+
<line x="8.0" y="42.0" />
|
| 277 |
+
<line x="8.0" y="120.0" />
|
| 278 |
+
<line x="0.0" y="120.0" />
|
| 279 |
+
<line x="0.0" y="35.0" />
|
| 280 |
+
<line x="21.5" y="35.0" />
|
| 281 |
+
<close />
|
| 282 |
+
</path>
|
| 283 |
+
<fillstroke />
|
| 284 |
+
<stroke />
|
| 285 |
+
<path>
|
| 286 |
+
<move x="72.5" y="50.0" />
|
| 287 |
+
<line x="90.0" y="50.0" />
|
| 288 |
+
<line x="90.0" y="121.0" />
|
| 289 |
+
<line x="81.0" y="121.0" />
|
| 290 |
+
<line x="81.0" y="56.0" />
|
| 291 |
+
<line x="72.5" y="56.0" />
|
| 292 |
+
<close />
|
| 293 |
+
</path>
|
| 294 |
+
<fillstroke />
|
| 295 |
+
<stroke />
|
| 296 |
+
<path>
|
| 297 |
+
<move x="22.0" y="4.0" />
|
| 298 |
+
<line x="72.7" y="4.0" />
|
| 299 |
+
</path>
|
| 300 |
+
<stroke />
|
| 301 |
+
<path>
|
| 302 |
+
<move x="22.0" y="10.0" />
|
| 303 |
+
<line x="72.7" y="10.0" />
|
| 304 |
+
</path>
|
| 305 |
+
<stroke />
|
| 306 |
+
</foreground>
|
| 307 |
+
</shape><shape h="57.0" w="56.0" aspect="variable" strokewidth="inherit" name="crusher_cone" displayName="crusher_cone"><foreground><rect x="7.72" y="0" w="40.55" h="32.09" /><fillstroke /><stroke /><rect x="0" y="44.67" w="56" h="11.33" /><fillstroke /><stroke /><rect x="0" y="32.09" w="56" h="12.58" /><fillstroke /><stroke /><rect x="5.79" y="32.09" w="4.51" h="12.58" /><fillstroke /><stroke /><rect x="15.61" y="32.09" w="4.51" h="12.58" /><fillstroke /><stroke /><rect x="25.75" y="32.09" w="4.51" h="12.58" /><fillstroke /><stroke /><rect x="36.05" y="32.09" w="4.51" h="12.58" /><fillstroke /><stroke /><rect x="45.7" y="32.09" w="4.51" h="12.58" /><fillstroke /><stroke /><path><move x="20.919999999999998" y="32.019999999999996" /><line x="28.0" y="10.940000000000001" /><line x="35.08" y="32.019999999999996" /><close /></path><fillstroke /><stroke /><path><move x="22.0" y="0.0" /><line x="15.5" y="32.89" /></path><fillstroke /><stroke /><path><move x="33.0" y="0.0" /><line x="40.5" y="32.89" /></path><fillstroke /><stroke /></foreground></shape><shape h="94.0" w="114.0" aspect="variable" strokewidth="inherit" name="crusher_jaw" displayName="crusher_jaw"><foreground><rect x="0" y="0" w="113" h="93" /><fillstroke /><stroke /><ellipse x="8.0" y="39.0" w="50.0" h="41.0" /><fillstroke /><stroke /><path><move x="84.75" y="93.0" /><line x="97.0" y="11.0" /><line x="113.0" y="11.0" /><line x="113.0" y="93.0" /><line x="84.57" y="93.07" /><close /></path><stroke /><path><move x="56.2" y="92.24" /><line x="61.0" y="9.0" /><line x="77.0" y="8.0" /><line x="83.75" y="89.83" /><close /></path><stroke /></foreground></shape><shape h="83.0" w="48.0" aspect="variable" strokewidth="inherit" name="cyclone" displayName="cyclone"><foreground><path><move x="44.0" y="41.0" /><line x="33.0" y="79.0" /><line x="10.999999999999998" y="79.0" /><line x="3.552713678800501e-15" y="41.0" /><close /></path><fillstroke /><stroke /><rect x="0" y="32" w="44" h="10.5" /><fillstroke /><stroke /><rect x="14.5" y="0" w="15" h="10" /><fillstroke /><stroke /><path><move x="44.0" y="32.0" /><line x="44.0" y="42.0" /><line x="33.0" y="79.0" /><line x="11.0" y="79.0" /><line x="0.0" y="42.0" /><line x="0.0" y="32.0" /></path><fillstroke /><stroke /><rect x="0" y="10" w="44" h="22" /><fillstroke /><stroke /></foreground></shape><shape h="73.0" w="222.0" aspect="variable" strokewidth="inherit" name="deaerator" displayName="deaerator"><foreground><roundrect arcsize="12" x="0" y="10" w="222" h="53" /><fillstroke /><stroke /><rect x="21" y="0" w="11" h="10" /><fillstroke /><stroke /><rect x="107" y="0" w="11" h="10" /><fillstroke /><stroke /><rect x="190" y="0" w="11" h="10" /><fillstroke /><stroke /><rect x="156" y="63" w="11" h="10" /><fillstroke /><stroke /><rect x="61" y="63" w="11" h="10" /><fillstroke /><stroke /></foreground></shape><shape h="119.0" w="37.0" aspect="variable" strokewidth="inherit" name="decomposer" displayName="decomposer"><foreground><rect x="0" y="0" w="36" h="96" /><fillstroke /><stroke /><path><move x="0.0" y="96.0" /><line x="36.0" y="96.0" /><line x="36.0" y="105.0" /><line x="18.0" y="119.0" /><line x="0.0" y="105.0" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="155.0" w="67.0" aspect="variable" strokewidth="inherit" name="direct-flow_evaporator" displayName="direct-flow_evaporator">
|
| 308 |
+
<foreground>
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
<path>
|
| 312 |
+
<move x="9.0" y="60.0" />
|
| 313 |
+
<curve x1="12.0" y1="60.0" x2="6.0" y2="101.5" x3="12.0" y3="143.0" />
|
| 314 |
+
<curve x1="9.0" y1="143.0" x2="3.0" y2="101.5" x3="9.0" y3="60.0" />
|
| 315 |
+
</path>
|
| 316 |
+
<fillstroke />
|
| 317 |
+
<stroke />
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
<path>
|
| 321 |
+
<move x="56.99999999999999" y="143.0" />
|
| 322 |
+
<curve x1="53.99999999999999" y1="143.0" x2="60.0" y2="101.5" x3="54.00000000000001" y3="60.0" />
|
| 323 |
+
<curve x1="57.00000000000001" y1="60.0" x2="63.0" y2="101.5" x3="56.99999999999999" y3="143.0" />
|
| 324 |
+
</path>
|
| 325 |
+
<fillstroke />
|
| 326 |
+
<stroke />
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
<roundrect arcsize="13" x="0" y="0" w="66" h="53" />
|
| 330 |
+
<fillstroke />
|
| 331 |
+
<stroke />
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
<path>
|
| 335 |
+
<move x="65.5" y="49.0" />
|
| 336 |
+
<line x="48.5" y="74.0" />
|
| 337 |
+
<line x="17.0" y="74.0" />
|
| 338 |
+
<line x="0.0" y="49.0" />
|
| 339 |
+
<close />
|
| 340 |
+
</path>
|
| 341 |
+
<fillstroke />
|
| 342 |
+
<stroke />
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
<rect x="16.75" y="74" w="32" h="52" />
|
| 346 |
+
<fillstroke />
|
| 347 |
+
<stroke />
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
<path>
|
| 351 |
+
<move x="0.0" y="155.0" />
|
| 352 |
+
<line x="17.0" y="126.0" />
|
| 353 |
+
<line x="48.5" y="126.0" />
|
| 354 |
+
<line x="65.5" y="155.0" />
|
| 355 |
+
<close />
|
| 356 |
+
</path>
|
| 357 |
+
<fillstroke />
|
| 358 |
+
<stroke />
|
| 359 |
+
</foreground>
|
| 360 |
+
</shape><shape h="56.0" w="163.0" aspect="variable" strokewidth="inherit" name="drum_dryer" displayName="drum_dryer"><foreground><rect x="0" y="31.25" w="15" h="19.75" /><fillstroke /><stroke /><roundrect arcsize="5.85" x="20" y="4.64" w="141" h="39" /><fillstroke /><stroke /><rect x="15" y="1" w="15" h="54" /><fillstroke /><stroke /><rect x="111" y="2" w="5" h="45" /><fillstroke /><stroke /><rect x="111" y="7" w="5" h="4" /><fillstroke /><stroke /><rect x="111" y="16" w="5" h="4" /><fillstroke /><stroke /><rect x="111" y="25" w="5" h="4" /><fillstroke /><stroke /><rect x="111" y="34" w="5" h="4" /><fillstroke /><stroke /><rect x="111" y="43" w="5" h="4" /><fillstroke /><stroke /><rect x="154" y="0" w="9" h="55" /><fillstroke /><stroke /></foreground></shape><shape h="115.0" w="139.0" aspect="variable" strokewidth="inherit" name="electric_motor" displayName="electric_motor"><foreground><rect x="13.6" y="0" w="26" h="115" /><fillstroke /><stroke /><rect x="39.6" y="15" w="84" h="85" /><fillstroke /><stroke /><rect x="48.6" y="0" w="65" h="115" /><fillstroke /><stroke /><rect x="122.6" y="11" w="16" h="93" /><fillstroke /><stroke /><path><move x="13.299999999999995" y="114.69999999999999" /><line x="-1.7763568394002505e-15" y="111.44999999999999" /><line x="5.329070518200751e-15" y="3.3399999999999963" /><line x="13.300000000000002" y="0.0899999999999963" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="78.0" w="40.0" aspect="variable" strokewidth="inherit" name="electrostatic_precipitator" displayName="electrostatic_precipitator">
|
| 361 |
+
<foreground>
|
| 362 |
+
<rect x="0" y="10.31" w="40" h="57.59" />
|
| 363 |
+
<fillstroke />
|
| 364 |
+
<stroke />
|
| 365 |
+
<path>
|
| 366 |
+
<move x="39.67" y="67.69999999999999" />
|
| 367 |
+
<line x="36.0" y="78.00999999999999" />
|
| 368 |
+
<line x="4.0" y="78.00999999999999" />
|
| 369 |
+
<line x="0.3299999999999983" y="67.69999999999999" />
|
| 370 |
+
<close />
|
| 371 |
+
</path>
|
| 372 |
+
<fillstroke />
|
| 373 |
+
<stroke />
|
| 374 |
+
<path>
|
| 375 |
+
<move x="0.33" y="10.31" />
|
| 376 |
+
<line x="4.0" y="0.0" />
|
| 377 |
+
<line x="36.0" y="0.0" />
|
| 378 |
+
<line x="39.67" y="10.31" />
|
| 379 |
+
<close />
|
| 380 |
+
</path>
|
| 381 |
+
<fillstroke />
|
| 382 |
+
<stroke />
|
| 383 |
+
<path>
|
| 384 |
+
<move x="23.0" y="25.86" />
|
| 385 |
+
<line x="16.0" y="35.56" />
|
| 386 |
+
<line x="25.0" y="35.56" />
|
| 387 |
+
<line x="13.72" y="47.55" />
|
| 388 |
+
</path>
|
| 389 |
+
<stroke />
|
| 390 |
+
<path>
|
| 391 |
+
<move x="19.15685424949238" y="46.292893218813454" />
|
| 392 |
+
<line x="10.318019484660535" y="50.18198051533946" />
|
| 393 |
+
<line x="14.20710678118655" y="41.34314575050762" />
|
| 394 |
+
<close />
|
| 395 |
+
</path>
|
| 396 |
+
<fillcolor color="#696969" />
|
| 397 |
+
<fillstroke />
|
| 398 |
+
<stroke />
|
| 399 |
+
</foreground>
|
| 400 |
+
</shape><shape h="244.0" w="131.0" aspect="variable" strokewidth="inherit" name="elevator" displayName="elevator">
|
| 401 |
+
<foreground>
|
| 402 |
+
|
| 403 |
+
<path>
|
| 404 |
+
<move x="1.24" y="216.38" />
|
| 405 |
+
<line x="50.47" y="216.38" />
|
| 406 |
+
<line x="50.47" y="0" />
|
| 407 |
+
<line x="122.29" y="0" />
|
| 408 |
+
<line x="130.296" y="27.62" />
|
| 409 |
+
<line x="78" y="27.62" />
|
| 410 |
+
<line x="78" y="244" />
|
| 411 |
+
<line x="9" y="244" />
|
| 412 |
+
<close />
|
| 413 |
+
</path>
|
| 414 |
+
<fillstroke />
|
| 415 |
+
<stroke />
|
| 416 |
+
|
| 417 |
+
</foreground>
|
| 418 |
+
</shape><shape h="244.0" w="131.0" aspect="variable" strokewidth="inherit" name="elevator_left" displayName="elevator_left">
|
| 419 |
+
<foreground>
|
| 420 |
+
|
| 421 |
+
<path>
|
| 422 |
+
<move x="0" y="27.62" />
|
| 423 |
+
<line x="8" y="0" />
|
| 424 |
+
<line x="78" y="0" />
|
| 425 |
+
<line x="78" y="216.38" />
|
| 426 |
+
<line x="130" y="216.38" />
|
| 427 |
+
<line x="122" y="244" />
|
| 428 |
+
<line x="50.47" y="244" />
|
| 429 |
+
<line x="50.47" y="27.62" />
|
| 430 |
+
<close />
|
| 431 |
+
</path>
|
| 432 |
+
<fillstroke />
|
| 433 |
+
<stroke />
|
| 434 |
+
|
| 435 |
+
</foreground>
|
| 436 |
+
</shape><shape h="40.0" w="40.0" aspect="variable" strokewidth="inherit" name="fan" displayName="fan"><foreground><ellipse x="0.0" y="0.0" w="40.0" h="40.0" /><fillstroke /><stroke /><path><move x="0.28" y="17.28" /><curve x1="35.28" y1="7.36" x2="35.28" x3="35.28" y2="7.36" y3="7.36" /></path><fillstroke /><stroke /><path><move x="0.2" y="22.44" /><curve x1="36.76" y1="31.08" x2="36.76" x3="36.76" y2="31.08" y3="31.08" /></path><fillstroke /><stroke /></foreground></shape><shape h="178.0" w="41.0" aspect="variable" strokewidth="inherit" name="feeder _power_line" displayName="feeder _power_line"><foreground><path><move x="19.36" y="169.0" /><line x="19.5" y="13.37" /></path><fillstroke /><stroke /><path><move x="19.51" y="8.12" /><line x="23.0" y="15.12" /><line x="19.5" y="13.37" /><line x="16.0" y="15.12" /><close /></path><fillstroke /><stroke /><rect x="8" y="85.84" w="23" h="20" /><fillstroke /><stroke /><path><move x="0.31" y="169.0" /><line x="0.29" y="138.86" /><line x="19.0" y="138.84" /></path><stroke /><path><move x="19.0" y="68.84" /><line x="38.86" y="68.86" /><line x="38.93" y="44.72" /></path><stroke /></foreground></shape><shape h="131.0" w="25.0" aspect="variable" strokewidth="inherit" name="feeder_busbar" displayName="feeder_busbar">
|
| 437 |
+
<foreground>
|
| 438 |
+
<ellipse x="0.2699999999999996" y="104.89" w="24.8" h="24.8" />
|
| 439 |
+
<fillstroke />
|
| 440 |
+
<stroke />
|
| 441 |
+
<path>
|
| 442 |
+
<move x="12.775898384862245" y="118.9" />
|
| 443 |
+
<line x="19.704101615137752" y="122.9" />
|
| 444 |
+
</path>
|
| 445 |
+
<fillstroke />
|
| 446 |
+
<stroke />
|
| 447 |
+
<path>
|
| 448 |
+
<move x="12.97" y="111.0" />
|
| 449 |
+
<line x="12.97" y="119.0" />
|
| 450 |
+
</path>
|
| 451 |
+
<fillstroke />
|
| 452 |
+
<stroke />
|
| 453 |
+
<path>
|
| 454 |
+
<move x="13.434101615137756" y="118.9" />
|
| 455 |
+
<line x="6.505898384862246" y="122.9" />
|
| 456 |
+
</path>
|
| 457 |
+
<fillstroke />
|
| 458 |
+
<stroke />
|
| 459 |
+
<ellipse x="0.40000000000000036" y="85.19" w="24.8" h="24.8" />
|
| 460 |
+
<fillstroke />
|
| 461 |
+
<stroke />
|
| 462 |
+
<path>
|
| 463 |
+
<move x="12.775898384862245" y="97.73" />
|
| 464 |
+
<line x="19.704101615137752" y="101.73" />
|
| 465 |
+
</path>
|
| 466 |
+
<fillstroke />
|
| 467 |
+
<stroke />
|
| 468 |
+
<path>
|
| 469 |
+
<move x="12.97" y="89.83" />
|
| 470 |
+
<line x="12.97" y="97.83" />
|
| 471 |
+
</path>
|
| 472 |
+
<fillstroke />
|
| 473 |
+
<stroke />
|
| 474 |
+
<path>
|
| 475 |
+
<move x="13.434101615137756" y="97.73" />
|
| 476 |
+
<line x="6.505898384862246" y="101.73" />
|
| 477 |
+
</path>
|
| 478 |
+
<fillstroke />
|
| 479 |
+
<stroke />
|
| 480 |
+
<path>
|
| 481 |
+
<move x="12.8" y="84.99" />
|
| 482 |
+
<line x="12.86" y="30.0" />
|
| 483 |
+
<line x="12.78" y="12.89" />
|
| 484 |
+
</path>
|
| 485 |
+
<fillstroke />
|
| 486 |
+
<stroke />
|
| 487 |
+
<path>
|
| 488 |
+
<move x="23.799999999999997" y="61.99" />
|
| 489 |
+
<line x="1.799999999999999" y="61.99" />
|
| 490 |
+
<line x="1.8000000000000025" y="42.99" />
|
| 491 |
+
<line x="23.800000000000004" y="42.99" />
|
| 492 |
+
<close />
|
| 493 |
+
</path>
|
| 494 |
+
<fillstroke />
|
| 495 |
+
<stroke />
|
| 496 |
+
<fillcolor color="#696969" />
|
| 497 |
+
<path>
|
| 498 |
+
<move x="12.76" y="7.64" />
|
| 499 |
+
<line x="15.12" y="14.63" />
|
| 500 |
+
<line x="12.78" y="12.89" />
|
| 501 |
+
<line x="10.46" y="14.65" />
|
| 502 |
+
<close />
|
| 503 |
+
</path>
|
| 504 |
+
<fillstroke />
|
| 505 |
+
<stroke />
|
| 506 |
+
|
| 507 |
+
<ellipse x="0.40000000000000036" y="104.89" w="24.8" h="24.8" />
|
| 508 |
+
|
| 509 |
+
<stroke />
|
| 510 |
+
</foreground>
|
| 511 |
+
</shape><shape h="191.0" w="39.0" aspect="variable" strokewidth="inherit" name="feeder_with_generator" displayName="feeder_with_generator">
|
| 512 |
+
<foreground>
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
<path>
|
| 516 |
+
<move x="17.36" y="162.28" />
|
| 517 |
+
<line x="17.51" y="0.28" />
|
| 518 |
+
</path>
|
| 519 |
+
<fillstroke />
|
| 520 |
+
<stroke />
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
<rect x="6" y="79.12" w="23" h="20" />
|
| 524 |
+
<fillstroke />
|
| 525 |
+
<stroke />
|
| 526 |
+
|
| 527 |
+
|
| 528 |
+
<path>
|
| 529 |
+
<move x="17.0" y="24.12" />
|
| 530 |
+
<line x="36.86" y="24.14" />
|
| 531 |
+
<line x="36.93" y="0.0" />
|
| 532 |
+
</path>
|
| 533 |
+
<stroke />
|
| 534 |
+
|
| 535 |
+
|
| 536 |
+
<ellipse x="0.0" y="157.28" w="33.3" h="33.3" />
|
| 537 |
+
<fillstroke />
|
| 538 |
+
<stroke />
|
| 539 |
+
|
| 540 |
+
|
| 541 |
+
<path>
|
| 542 |
+
<move x="4.58" y="173.93" />
|
| 543 |
+
<curve x1="10.0" y1="160.98" x2="16.0" y2="172.98" x3="17.0" y3="176.98" />
|
| 544 |
+
<curve x1="18.73" y1="180.93" x2="22.0" y2="184.98" x3="28.73" y3="173.93" />
|
| 545 |
+
</path>
|
| 546 |
+
<fillstroke />
|
| 547 |
+
<stroke />
|
| 548 |
+
</foreground>
|
| 549 |
+
</shape><shape h="191.0" w="188.0" aspect="variable" strokewidth="inherit" name="filling_station" displayName="filling_station">
|
| 550 |
+
<foreground>
|
| 551 |
+
<rect x="0" y="0" w="188" h="190.64" />
|
| 552 |
+
<fillstroke />
|
| 553 |
+
<stroke />
|
| 554 |
+
|
| 555 |
+
<path>
|
| 556 |
+
<move x="21" y="130.77" />
|
| 557 |
+
<line x="31" y="130.77" />
|
| 558 |
+
<arc sweep-flag="1" rx="5" ry="5" x="41" y="130.77" />
|
| 559 |
+
<line x="51" y="130.77" />
|
| 560 |
+
<arc sweep-flag="1" large-arc-flag="1" rx="5" ry="6.5" x="51" y="136.24" />
|
| 561 |
+
<line x="41" y="136.24" />
|
| 562 |
+
<arc sweep-flag="1" rx="5" ry="5" x="31" y="136.24" />
|
| 563 |
+
<line x="21" y="136.24" />
|
| 564 |
+
<arc sweep-flag="1" large-arc-flag="1" rx="5" ry="6.5" x="21" y="130.77" />
|
| 565 |
+
<close />
|
| 566 |
+
</path>
|
| 567 |
+
<fillstroke />
|
| 568 |
+
<stroke />
|
| 569 |
+
|
| 570 |
+
<rect x="40" y="29.32" w="67" h="49" />
|
| 571 |
+
<fillstroke />
|
| 572 |
+
<stroke />
|
| 573 |
+
|
| 574 |
+
<rect x="40" y="29.32" w="34" h="21" />
|
| 575 |
+
<fillstroke />
|
| 576 |
+
<stroke />
|
| 577 |
+
|
| 578 |
+
<rect x="60" y="57.32" w="24" h="14" />
|
| 579 |
+
<fillstroke />
|
| 580 |
+
<stroke />
|
| 581 |
+
|
| 582 |
+
<rect x="107" y="37.32" w="7" h="17" />
|
| 583 |
+
<fillstroke />
|
| 584 |
+
<stroke />
|
| 585 |
+
|
| 586 |
+
<ellipse x="85.0" y="37.32" w="9.0" h="13.0" />
|
| 587 |
+
<fillstroke />
|
| 588 |
+
<stroke />
|
| 589 |
+
|
| 590 |
+
<rect x="68" y="105.32" w="52" h="56" />
|
| 591 |
+
<fillstroke />
|
| 592 |
+
<stroke />
|
| 593 |
+
|
| 594 |
+
<rect x="126" y="105.32" w="52" h="56" />
|
| 595 |
+
<fillstroke />
|
| 596 |
+
<stroke />
|
| 597 |
+
|
| 598 |
+
<ellipse x="129.0" y="125.32" w="11.0" h="16.0" />
|
| 599 |
+
<fillstroke />
|
| 600 |
+
<stroke />
|
| 601 |
+
|
| 602 |
+
<ellipse x="146.5" y="125.32" w="11.0" h="16.0" />
|
| 603 |
+
<fillstroke />
|
| 604 |
+
<stroke />
|
| 605 |
+
|
| 606 |
+
<ellipse x="164.0" y="125.32" w="11.0" h="16.0" />
|
| 607 |
+
<fillstroke />
|
| 608 |
+
<stroke />
|
| 609 |
+
|
| 610 |
+
<path>
|
| 611 |
+
<move x="79" y="130.77" />
|
| 612 |
+
<line x="89" y="130.77" />
|
| 613 |
+
<arc sweep-flag="1" rx="5" ry="5" x="99" y="130.77" />
|
| 614 |
+
<line x="109" y="130.77" />
|
| 615 |
+
<arc sweep-flag="1" large-arc-flag="1" rx="5" ry="6.5" x="109" y="136.24" />
|
| 616 |
+
<line x="99" y="136.24" />
|
| 617 |
+
<arc sweep-flag="1" rx="5" ry="5" x="89" y="136.24" />
|
| 618 |
+
<line x="79" y="136.24" />
|
| 619 |
+
<arc sweep-flag="1" large-arc-flag="1" rx="5" ry="6.5" x="79" y="130.77" />
|
| 620 |
+
<close />
|
| 621 |
+
</path>
|
| 622 |
+
<fillstroke />
|
| 623 |
+
<stroke />
|
| 624 |
+
|
| 625 |
+
<rect x="10" y="105.32" w="52" h="56" />
|
| 626 |
+
<stroke />
|
| 627 |
+
</foreground>
|
| 628 |
+
</shape><shape h="40.0" w="73.0" aspect="variable" strokewidth="inherit" name="filter" displayName="filter">
|
| 629 |
+
<foreground>
|
| 630 |
+
|
| 631 |
+
|
| 632 |
+
<roundrect arcsize="6" x="3.13" y="0" w="65.75" h="22.4" />
|
| 633 |
+
<fillstroke />
|
| 634 |
+
<stroke />
|
| 635 |
+
|
| 636 |
+
|
| 637 |
+
<path>
|
| 638 |
+
<move x="72.0" y="15.360000000000003" />
|
| 639 |
+
<line x="67.39" y="28.000000000000004" />
|
| 640 |
+
<line x="4.609999999999999" y="27.999999999999996" />
|
| 641 |
+
<line x="0.0" y="15.359999999999996" />
|
| 642 |
+
<close />
|
| 643 |
+
</path>
|
| 644 |
+
<fillstroke />
|
| 645 |
+
<stroke />
|
| 646 |
+
|
| 647 |
+
|
| 648 |
+
<path>
|
| 649 |
+
<move x="60.39999999999999" y="28.16" />
|
| 650 |
+
<line x="57.78999999999999" y="40.0" />
|
| 651 |
+
<line x="15.029999999999994" y="39.99999999999999" />
|
| 652 |
+
<line x="12.419999999999995" y="28.159999999999993" />
|
| 653 |
+
<close />
|
| 654 |
+
</path>
|
| 655 |
+
<fillstroke />
|
| 656 |
+
<stroke />
|
| 657 |
+
</foreground>
|
| 658 |
+
</shape><shape h="61.0" w="81.0" aspect="variable" strokewidth="inherit" name="filter_dedusting" displayName="filter_dedusting"><foreground><rect x="0" y="0" w="81" h="60" /><fillstroke /><stroke /><path><move x="0.0" y="20.0" /><line x="81.0" y="20.0" /></path><fillstroke /><stroke /><path><move x="0.0" y="41.43" /><line x="81.0" y="41.43" /></path><fillstroke /><stroke /><path><move x="19.919999999999998" y="0.0" /><line x="19.920000000000005" y="60.0" /></path><fillstroke /><stroke /><path><move x="40.5" y="0.0" /><line x="40.5" y="60.0" /></path><fillstroke /><stroke /><path><move x="59.75" y="0.0" /><line x="59.75" y="60.0" /></path><fillstroke /><stroke /></foreground></shape><shape h="38.0" w="101.0" aspect="variable" strokewidth="inherit" name="fire" displayName="fire">
|
| 659 |
+
<foreground>
|
| 660 |
+
<path>
|
| 661 |
+
<move x="-0.41" y="14.7" />
|
| 662 |
+
<line x="16.83" y="3.99" />
|
| 663 |
+
<line x="14.01" y="10.8" />
|
| 664 |
+
<line x="42.85" y="-0.3" />
|
| 665 |
+
<line x="38.16" y="4.71" />
|
| 666 |
+
<line x="64.17" y="2.48" />
|
| 667 |
+
<line x="59.48" y="5.43" />
|
| 668 |
+
<line x="82.35" y="8.03" />
|
| 669 |
+
<line x="80.81" y="11.15" />
|
| 670 |
+
<line x="100.0" y="19.02" />
|
| 671 |
+
<line x="76.54" y="28.33" />
|
| 672 |
+
<line x="79.84" y="32.45" />
|
| 673 |
+
<line x="56.64" y="32.45" />
|
| 674 |
+
<line x="61.03" y="34.67" />
|
| 675 |
+
<line x="35.33" y="32.45" />
|
| 676 |
+
<line x="39.71" y="37.45" />
|
| 677 |
+
<line x="13.99" y="25.46" />
|
| 678 |
+
<line x="16.83" y="31.19" />
|
| 679 |
+
<line x="-0.41" y="26.35" />
|
| 680 |
+
<line x="-0.41" y="14.2" />
|
| 681 |
+
<close />
|
| 682 |
+
</path>
|
| 683 |
+
<fillstroke />
|
| 684 |
+
<stroke />
|
| 685 |
+
</foreground>
|
| 686 |
+
</shape><shape h="51.0" w="61.0" aspect="variable" strokewidth="inherit" name="gate_doubleout" displayName="gate_doubleout"><foreground><path><move x="33.41974488218369" y="19.977929565774033" /><line x="16.6368983545521" y="43.94631838166994" /><line x="4.112063597373407" y="35.17633466986245" /><line x="20.894910125005005" y="11.207945853966542" /><close /></path><fillstroke /><stroke /><path><move x="40.23116259018858" y="11.205490097887171" /><line x="57.01400911782019" y="35.17387891378307" /><line x="44.4891743606415" y="43.94386262559057" /><line x="27.706327833009894" y="19.975473809694666" /><close /></path><fillstroke /><stroke /><path><move x="18.4" y="0.0" /><line x="42.57" y="0.0" /><line x="42.57" y="15.11" /><line x="30.49" y="24.17" /><line x="18.4" y="15.11" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="25.0" w="25.0" aspect="variable" strokewidth="inherit" name="gate_valve" displayName="gate_valve"><foreground><rect x="0" y="0" w="24" h="24" /><fillstroke /><stroke /><path><move x="24.0" y="24.0" /><curve x1="0.0" y1="0.0" x2="0.0" x3="0.0" y2="0.0" y3="0.0" /></path><fillstroke /><stroke /></foreground></shape><shape h="194.0" w="191.0" aspect="variable" strokewidth="inherit" name="GraphiteDippingSuspension" displayName="GraphiteDippingSuspension">
|
| 687 |
+
<foreground>
|
| 688 |
+
<rect x="0" y="0" w="191" h="194" />
|
| 689 |
+
<fillstroke />
|
| 690 |
+
<stroke />
|
| 691 |
+
|
| 692 |
+
<path>
|
| 693 |
+
<move x="92" y="18" />
|
| 694 |
+
<line x="104" y="18" />
|
| 695 |
+
<line x="104" y="140" />
|
| 696 |
+
<line x="135" y="140" />
|
| 697 |
+
<line x="135" y="178" />
|
| 698 |
+
<line x="123" y="178" />
|
| 699 |
+
<line x="123" y="152" />
|
| 700 |
+
<line x="104" y="152" />
|
| 701 |
+
<line x="104" y="178" />
|
| 702 |
+
<line x="92" y="178" />
|
| 703 |
+
<line x="92" y="152" />
|
| 704 |
+
<line x="73" y="152" />
|
| 705 |
+
<line x="73" y="178" />
|
| 706 |
+
<line x="61" y="178" />
|
| 707 |
+
<line x="61" y="140" />
|
| 708 |
+
<line x="92" y="140" />
|
| 709 |
+
<close />
|
| 710 |
+
</path>
|
| 711 |
+
<fillstroke />
|
| 712 |
+
<stroke />
|
| 713 |
+
|
| 714 |
+
<ellipse x="149.0" y="78.0" w="14.0" h="9.0" />
|
| 715 |
+
<fillstroke />
|
| 716 |
+
<stroke />
|
| 717 |
+
<path>
|
| 718 |
+
<move x="112.26" y="81.49" />
|
| 719 |
+
<line x="151.73" y="78.88" />
|
| 720 |
+
</path>
|
| 721 |
+
<fillstroke />
|
| 722 |
+
<stroke />
|
| 723 |
+
<path>
|
| 724 |
+
<move x="112.89" y="90.34" />
|
| 725 |
+
<line x="149.77" y="80.29" />
|
| 726 |
+
</path>
|
| 727 |
+
<fillstroke />
|
| 728 |
+
<stroke />
|
| 729 |
+
<path>
|
| 730 |
+
<move x="116.68" y="97.38" />
|
| 731 |
+
<line x="149.21" y="81.19" />
|
| 732 |
+
</path>
|
| 733 |
+
<fillstroke />
|
| 734 |
+
<stroke />
|
| 735 |
+
<path>
|
| 736 |
+
<move x="124.51" y="100.73" />
|
| 737 |
+
<line x="149.32" y="81.63" />
|
| 738 |
+
</path>
|
| 739 |
+
<fillstroke />
|
| 740 |
+
<stroke />
|
| 741 |
+
<ellipse x="149.0" y="78.0" w="14.0" h="9.0" />
|
| 742 |
+
<fillstroke />
|
| 743 |
+
<stroke />
|
| 744 |
+
<ellipse x="32.0" y="78.0" w="14.0" h="9.0" />
|
| 745 |
+
<fillstroke />
|
| 746 |
+
<stroke />
|
| 747 |
+
<path>
|
| 748 |
+
<move x="45.27" y="80.12" />
|
| 749 |
+
<line x="84.0" y="81.0" />
|
| 750 |
+
</path>
|
| 751 |
+
<fillstroke />
|
| 752 |
+
<stroke />
|
| 753 |
+
<path>
|
| 754 |
+
<move x="45.86" y="81.4" />
|
| 755 |
+
<line x="85.0" y="90.0" />
|
| 756 |
+
</path>
|
| 757 |
+
<fillstroke />
|
| 758 |
+
<stroke />
|
| 759 |
+
<path>
|
| 760 |
+
<move x="46.0" y="82.5" />
|
| 761 |
+
<line x="72.34" y="100.06" />
|
| 762 |
+
</path>
|
| 763 |
+
<fillstroke />
|
| 764 |
+
<stroke />
|
| 765 |
+
<path>
|
| 766 |
+
<move x="45.86" y="81.63" />
|
| 767 |
+
<line x="83.0" y="98.0" />
|
| 768 |
+
</path>
|
| 769 |
+
<fillstroke />
|
| 770 |
+
<stroke />
|
| 771 |
+
<ellipse x="32.0" y="78.0" w="14.0" h="9.0" />
|
| 772 |
+
<fillstroke />
|
| 773 |
+
<stroke />
|
| 774 |
+
<path>
|
| 775 |
+
<move x="45.27" y="80.12" />
|
| 776 |
+
<line x="84.0" y="81.0" />
|
| 777 |
+
</path>
|
| 778 |
+
<fillstroke />
|
| 779 |
+
<stroke />
|
| 780 |
+
<path>
|
| 781 |
+
<move x="45.86" y="81.4" />
|
| 782 |
+
<line x="85.0" y="90.0" />
|
| 783 |
+
</path>
|
| 784 |
+
<fillstroke />
|
| 785 |
+
<stroke />
|
| 786 |
+
<path>
|
| 787 |
+
<move x="46.0" y="82.5" />
|
| 788 |
+
<line x="72.34" y="100.06" />
|
| 789 |
+
</path>
|
| 790 |
+
<fillstroke />
|
| 791 |
+
<stroke />
|
| 792 |
+
<path>
|
| 793 |
+
<move x="45.86" y="81.63" />
|
| 794 |
+
<line x="83.0" y="98.0" />
|
| 795 |
+
</path>
|
| 796 |
+
<fillstroke />
|
| 797 |
+
<stroke />
|
| 798 |
+
<path>
|
| 799 |
+
<move x="112.26" y="81.49" />
|
| 800 |
+
<line x="151.73" y="78.88" />
|
| 801 |
+
</path>
|
| 802 |
+
<fillstroke />
|
| 803 |
+
<stroke />
|
| 804 |
+
<path>
|
| 805 |
+
<move x="112.89" y="90.34" />
|
| 806 |
+
<line x="149.77" y="80.29" />
|
| 807 |
+
</path>
|
| 808 |
+
<fillstroke />
|
| 809 |
+
<stroke />
|
| 810 |
+
<path>
|
| 811 |
+
<move x="116.68" y="97.38" />
|
| 812 |
+
<line x="149.21" y="81.19" />
|
| 813 |
+
</path>
|
| 814 |
+
<fillstroke />
|
| 815 |
+
<stroke />
|
| 816 |
+
<path>
|
| 817 |
+
<move x="124.51" y="100.73" />
|
| 818 |
+
<line x="149.32" y="81.63" />
|
| 819 |
+
</path>
|
| 820 |
+
<fillstroke />
|
| 821 |
+
<stroke />
|
| 822 |
+
</foreground>
|
| 823 |
+
</shape><shape h="59.0" w="88.0" aspect="variable" strokewidth="inherit" name="grizzly" displayName="grizzly">
|
| 824 |
+
<foreground>
|
| 825 |
+
<path>
|
| 826 |
+
<move x="42.0" y="59.0" />
|
| 827 |
+
<line x="88.0" y="59" />
|
| 828 |
+
<line x="88.0" y="46.5" />
|
| 829 |
+
<line x="46.0" y="0.5" />
|
| 830 |
+
<line x="0.0" y="0.5" />
|
| 831 |
+
<line x="42.0" y="47.0" />
|
| 832 |
+
<line x="42.0" y="59.0" />
|
| 833 |
+
<close />
|
| 834 |
+
</path>
|
| 835 |
+
<fillstroke />
|
| 836 |
+
<stroke />
|
| 837 |
+
<path>
|
| 838 |
+
<move x="76.0" y="59.0" />
|
| 839 |
+
<line x="76.0" y="47.0" />
|
| 840 |
+
<line x="33.0" y="0.5" />
|
| 841 |
+
</path>
|
| 842 |
+
<stroke />
|
| 843 |
+
<path>
|
| 844 |
+
<move x="54.0" y="59.0" />
|
| 845 |
+
<line x="54.0" y="47.0" />
|
| 846 |
+
<line x="11.0" y="0.5" />
|
| 847 |
+
</path>
|
| 848 |
+
<stroke />
|
| 849 |
+
<path>
|
| 850 |
+
<move x="65.0" y="59.0" />
|
| 851 |
+
<line x="65.0" y="47.0" />
|
| 852 |
+
<line x="22.0" y="0.5" />
|
| 853 |
+
</path>
|
| 854 |
+
<stroke />
|
| 855 |
+
</foreground>
|
| 856 |
+
</shape><shape h="82.0" w="77.0" aspect="variable" strokewidth="inherit" name="hammer_mill" displayName="hammer_mill"><foreground><path><move x="-0.0026774517975631795" y="19.25891126772399" /><line x="38.34372329194891" y="19.096276708051086" /><line x="38.18108873227601" y="57.442677451797564" /><close /></path><fillstroke /><stroke /><roundrect arcsize="8.7" x="9.28" y="23.61" w="67" h="58" /><fillstroke /><stroke /><ellipse x="19.28" y="30.61" w="47.16" h="42.0" /><fillstroke /><stroke /></foreground></shape><shape h="38.0" w="56.0" aspect="variable" strokewidth="inherit" name="heater" displayName="heater">
|
| 857 |
+
<foreground>
|
| 858 |
+
<rect x="0" y="0" w="56" h="38" />
|
| 859 |
+
<fillstroke />
|
| 860 |
+
<stroke />
|
| 861 |
+
<path>
|
| 862 |
+
<move x="14.0" y="38.0" />
|
| 863 |
+
<line x="14.0" y="20.0" />
|
| 864 |
+
</path>
|
| 865 |
+
<stroke />
|
| 866 |
+
<path>
|
| 867 |
+
<move x="42.0" y="38.0" />
|
| 868 |
+
<line x="42.0" y="20.0" />
|
| 869 |
+
</path>
|
| 870 |
+
<stroke />
|
| 871 |
+
<path>
|
| 872 |
+
<move x="14.0" y="20.0" />
|
| 873 |
+
<curve x1="14.32" y1="0.0" x2="19.73" y2="19.5" x3="19.73" y3="19.5" />
|
| 874 |
+
</path>
|
| 875 |
+
<stroke />
|
| 876 |
+
<path>
|
| 877 |
+
<move x="19.73" y="19.5" />
|
| 878 |
+
<curve x1="22.91" y1="40.5" x2="25.45" y2="19.0" x3="25.45" y3="19.0" />
|
| 879 |
+
<curve x1="28.0" y1="0.5" x2="31.18" y2="19.5" x3="31.18" y3="19.5" />
|
| 880 |
+
</path>
|
| 881 |
+
<stroke />
|
| 882 |
+
<path>
|
| 883 |
+
<move x="31.18" y="19.5" />
|
| 884 |
+
<curve x1="34.05" y1="40.5" x2="37.55" y2="18.75" x3="37.55" y3="18.75" />
|
| 885 |
+
<curve x1="41.05" y1="0.0" x2="42.0" y2="20.0" x3="42.0" y3="20.0" />
|
| 886 |
+
</path>
|
| 887 |
+
<stroke />
|
| 888 |
+
</foreground>
|
| 889 |
+
</shape><shape h="51.0" w="50.0" aspect="variable" strokewidth="inherit" name="heat_exchanger" displayName="heat_exchanger">
|
| 890 |
+
<foreground>
|
| 891 |
+
<path>
|
| 892 |
+
<move x="25.0" y="0.0" />
|
| 893 |
+
<line x="50.0" y="25.0" />
|
| 894 |
+
<line x="25.0" y="50.0" />
|
| 895 |
+
<line x="0.0" y="25.0" />
|
| 896 |
+
<close />
|
| 897 |
+
</path>
|
| 898 |
+
<fillstroke />
|
| 899 |
+
<stroke />
|
| 900 |
+
<path>
|
| 901 |
+
<move x="24.95" y="50.0" />
|
| 902 |
+
<line x="25.0" y="32.0" />
|
| 903 |
+
<line x="24.95" y="0.0" />
|
| 904 |
+
</path>
|
| 905 |
+
<fillcolor color="#696969" />
|
| 906 |
+
<fillstroke />
|
| 907 |
+
<stroke />
|
| 908 |
+
<path>
|
| 909 |
+
<move x="28.5" y="40.5" />
|
| 910 |
+
<line x="25.0" y="48.5" />
|
| 911 |
+
<line x="21.5" y="40.5" />
|
| 912 |
+
<close />
|
| 913 |
+
</path>
|
| 914 |
+
<fillstroke />
|
| 915 |
+
<stroke />
|
| 916 |
+
<path>
|
| 917 |
+
<move x="21.5" y="9.5" />
|
| 918 |
+
<line x="25.0" y="1.5" />
|
| 919 |
+
<line x="28.5" y="9.5" />
|
| 920 |
+
<close />
|
| 921 |
+
</path>
|
| 922 |
+
<fillstroke />
|
| 923 |
+
<stroke />
|
| 924 |
+
</foreground>
|
| 925 |
+
</shape><shape h="119.0" w="60.0" aspect="variable" strokewidth="inherit" name="ligature_feeding_machine" displayName="ligature_feeding_machine"><foreground><path><move x="60.0" y="0.0" /><line x="60.0" y="118.0" /><line x="3.552713678800501e-15" y="118.0" /><line x="-3.552713678800501e-15" y="0.0" /><close /></path><fillstroke /><stroke /><ellipse x="3.5" y="4.0" w="53.0" h="53.0" /><stroke /><ellipse x="3.5" y="60.0" w="53.0" h="53.0" /><stroke /></foreground></shape><shape h="113.0" w="71.0" aspect="variable" strokewidth="inherit" name="loeshe_mill" displayName="loeshe_mill"><foreground><rect x="0" y="4" w="71" h="34" /><fillstroke /><stroke /><rect x="5" y="38" w="61" h="71" /><fillstroke /><stroke /><rect x="0" y="109" w="71" h="4" /><fillstroke /><stroke /><rect x="19.5" y="0" w="32" h="4" /><fillstroke /><stroke /></foreground></shape><shape h="101.0" w="58.0" aspect="variable" strokewidth="inherit" name="LVAZ" displayName="LVAZ"><foreground><path><move x="0.05" y="8.0" /><line x="56.05" y="8.0" /><line x="56.05" y="80.0" /><line x="28.05" y="100.0" /><line x="0.05" y="80.0" /><close /></path><fillstroke /><stroke /><ellipse x="0.03999999999999915" y="0.0" w="56.0" h="17.0" /><fillstroke /><stroke /><path><move x="0.04" y="80.0" /><line x="56.04" y="80.0" /></path><fillstroke /><stroke /></foreground></shape><shape h="171.0" w="178.0" aspect="variable" strokewidth="inherit" name="MachineCleaningRod" displayName="MachineCleaningRod">
|
| 926 |
+
<foreground>
|
| 927 |
+
<rect x="0.26" y="0.24" w="178" h="171" />
|
| 928 |
+
<fillstroke />
|
| 929 |
+
<stroke />
|
| 930 |
+
<path>
|
| 931 |
+
<move x="85.03" y="49.6" />
|
| 932 |
+
<line x="93.49" y="49.6" />
|
| 933 |
+
<line x="93.49" y="134.42" />
|
| 934 |
+
<line x="115.36" y="134.42" />
|
| 935 |
+
<line x="115.36" y="161.54" />
|
| 936 |
+
<line x="106.89" y="161.54" />
|
| 937 |
+
<line x="106.89" y="142.76" />
|
| 938 |
+
<line x="93.49" y="142.76" />
|
| 939 |
+
<line x="93.49" y="161.54" />
|
| 940 |
+
<line x="85.03" y="161.54" />
|
| 941 |
+
<line x="85.03" y="142.76" />
|
| 942 |
+
<line x="71.63" y="142.76" />
|
| 943 |
+
<line x="71.63" y="161.54" />
|
| 944 |
+
<line x="63.17" y="161.54" />
|
| 945 |
+
<line x="63.17" y="134.42" />
|
| 946 |
+
<line x="85.03" y="134.42" />
|
| 947 |
+
<close />
|
| 948 |
+
</path>
|
| 949 |
+
<fillstroke />
|
| 950 |
+
<stroke />
|
| 951 |
+
<rect x="13.77" y="24.92" w="150.97" h="14.1" />
|
| 952 |
+
<fillstroke />
|
| 953 |
+
<stroke />
|
| 954 |
+
<rect x="40.8" y="39.02" w="9.32" h="93.43" />
|
| 955 |
+
<fillstroke />
|
| 956 |
+
<stroke />
|
| 957 |
+
<path>
|
| 958 |
+
<move x="25.89" y="125.4" />
|
| 959 |
+
<line x="42.66" y="125.4" />
|
| 960 |
+
</path>
|
| 961 |
+
<fillstroke />
|
| 962 |
+
<stroke />
|
| 963 |
+
<path>
|
| 964 |
+
<move x="25.89" y="120.99" />
|
| 965 |
+
<line x="42.66" y="120.99" />
|
| 966 |
+
</path>
|
| 967 |
+
<fillstroke />
|
| 968 |
+
<stroke />
|
| 969 |
+
<path>
|
| 970 |
+
<move x="25.89" y="116.59" />
|
| 971 |
+
<line x="42.66" y="116.59" />
|
| 972 |
+
</path>
|
| 973 |
+
<fillstroke />
|
| 974 |
+
<stroke />
|
| 975 |
+
<path>
|
| 976 |
+
<move x="25.89" y="112.18" />
|
| 977 |
+
<line x="42.66" y="112.18" />
|
| 978 |
+
</path>
|
| 979 |
+
<fillstroke />
|
| 980 |
+
<stroke />
|
| 981 |
+
<path>
|
| 982 |
+
<move x="25.89" y="107.77" />
|
| 983 |
+
<line x="42.66" y="107.77" />
|
| 984 |
+
</path>
|
| 985 |
+
<fillstroke />
|
| 986 |
+
<stroke />
|
| 987 |
+
<path>
|
| 988 |
+
<move x="25.89" y="103.37" />
|
| 989 |
+
<line x="42.66" y="103.37" />
|
| 990 |
+
</path>
|
| 991 |
+
<fillstroke />
|
| 992 |
+
<stroke />
|
| 993 |
+
<path>
|
| 994 |
+
<move x="25.89" y="98.96" />
|
| 995 |
+
<line x="42.66" y="98.96" />
|
| 996 |
+
</path>
|
| 997 |
+
<fillstroke />
|
| 998 |
+
<stroke />
|
| 999 |
+
<path>
|
| 1000 |
+
<move x="25.89" y="94.55" />
|
| 1001 |
+
<line x="42.66" y="94.55" />
|
| 1002 |
+
</path>
|
| 1003 |
+
<fillstroke />
|
| 1004 |
+
<stroke />
|
| 1005 |
+
<path>
|
| 1006 |
+
<move x="25.89" y="90.14" />
|
| 1007 |
+
<line x="42.66" y="90.14" />
|
| 1008 |
+
</path>
|
| 1009 |
+
<fillstroke />
|
| 1010 |
+
<stroke />
|
| 1011 |
+
<path>
|
| 1012 |
+
<move x="25.89" y="85.74" />
|
| 1013 |
+
<line x="42.66" y="85.74" />
|
| 1014 |
+
</path>
|
| 1015 |
+
<fillstroke />
|
| 1016 |
+
<stroke />
|
| 1017 |
+
<path>
|
| 1018 |
+
<move x="25.89" y="81.33" />
|
| 1019 |
+
<line x="42.66" y="81.33" />
|
| 1020 |
+
</path>
|
| 1021 |
+
<fillstroke />
|
| 1022 |
+
<stroke />
|
| 1023 |
+
<path>
|
| 1024 |
+
<move x="25.89" y="76.92" />
|
| 1025 |
+
<line x="42.66" y="76.92" />
|
| 1026 |
+
</path>
|
| 1027 |
+
<fillstroke />
|
| 1028 |
+
<stroke />
|
| 1029 |
+
<path>
|
| 1030 |
+
<move x="25.89" y="72.52" />
|
| 1031 |
+
<line x="42.66" y="72.52" />
|
| 1032 |
+
</path>
|
| 1033 |
+
<fillstroke />
|
| 1034 |
+
<stroke />
|
| 1035 |
+
<path>
|
| 1036 |
+
<move x="25.89" y="68.11" />
|
| 1037 |
+
<line x="42.66" y="68.11" />
|
| 1038 |
+
</path>
|
| 1039 |
+
<fillstroke />
|
| 1040 |
+
<stroke />
|
| 1041 |
+
<path>
|
| 1042 |
+
<move x="25.89" y="63.7" />
|
| 1043 |
+
<line x="42.66" y="63.7" />
|
| 1044 |
+
</path>
|
| 1045 |
+
<fillstroke />
|
| 1046 |
+
<stroke />
|
| 1047 |
+
<path>
|
| 1048 |
+
<move x="25.89" y="59.29" />
|
| 1049 |
+
<line x="42.66" y="59.29" />
|
| 1050 |
+
</path>
|
| 1051 |
+
<fillstroke />
|
| 1052 |
+
<stroke />
|
| 1053 |
+
<path>
|
| 1054 |
+
<move x="25.89" y="54.89" />
|
| 1055 |
+
<line x="42.66" y="54.89" />
|
| 1056 |
+
</path>
|
| 1057 |
+
<fillstroke />
|
| 1058 |
+
<stroke />
|
| 1059 |
+
<path>
|
| 1060 |
+
<move x="47.32" y="119.23" />
|
| 1061 |
+
<line x="64.1" y="119.23" />
|
| 1062 |
+
</path>
|
| 1063 |
+
<fillstroke />
|
| 1064 |
+
<stroke />
|
| 1065 |
+
<path>
|
| 1066 |
+
<move x="47.32" y="114.82" />
|
| 1067 |
+
<line x="64.1" y="114.82" />
|
| 1068 |
+
</path>
|
| 1069 |
+
<fillstroke />
|
| 1070 |
+
<stroke />
|
| 1071 |
+
<path>
|
| 1072 |
+
<move x="47.32" y="110.42" />
|
| 1073 |
+
<line x="64.1" y="110.42" />
|
| 1074 |
+
</path>
|
| 1075 |
+
<fillstroke />
|
| 1076 |
+
<stroke />
|
| 1077 |
+
<path>
|
| 1078 |
+
<move x="47.32" y="106.01" />
|
| 1079 |
+
<line x="64.1" y="106.01" />
|
| 1080 |
+
</path>
|
| 1081 |
+
<fillstroke />
|
| 1082 |
+
<stroke />
|
| 1083 |
+
<path>
|
| 1084 |
+
<move x="47.32" y="101.6" />
|
| 1085 |
+
<line x="64.1" y="101.6" />
|
| 1086 |
+
</path>
|
| 1087 |
+
<fillstroke />
|
| 1088 |
+
<stroke />
|
| 1089 |
+
<path>
|
| 1090 |
+
<move x="47.32" y="97.2" />
|
| 1091 |
+
<line x="64.1" y="97.2" />
|
| 1092 |
+
</path>
|
| 1093 |
+
<fillstroke />
|
| 1094 |
+
<stroke />
|
| 1095 |
+
<path>
|
| 1096 |
+
<move x="47.32" y="92.79" />
|
| 1097 |
+
<line x="64.1" y="92.79" />
|
| 1098 |
+
</path>
|
| 1099 |
+
<fillstroke />
|
| 1100 |
+
<stroke />
|
| 1101 |
+
<path>
|
| 1102 |
+
<move x="47.32" y="88.38" />
|
| 1103 |
+
<line x="64.1" y="88.38" />
|
| 1104 |
+
</path>
|
| 1105 |
+
<fillstroke />
|
| 1106 |
+
<stroke />
|
| 1107 |
+
<path>
|
| 1108 |
+
<move x="47.32" y="83.97" />
|
| 1109 |
+
<line x="64.1" y="83.97" />
|
| 1110 |
+
</path>
|
| 1111 |
+
<fillstroke />
|
| 1112 |
+
<stroke />
|
| 1113 |
+
<path>
|
| 1114 |
+
<move x="47.32" y="79.57" />
|
| 1115 |
+
<line x="64.1" y="79.57" />
|
| 1116 |
+
</path>
|
| 1117 |
+
<fillstroke />
|
| 1118 |
+
<stroke />
|
| 1119 |
+
<path>
|
| 1120 |
+
<move x="47.32" y="75.16" />
|
| 1121 |
+
<line x="64.1" y="75.16" />
|
| 1122 |
+
</path>
|
| 1123 |
+
<fillstroke />
|
| 1124 |
+
<stroke />
|
| 1125 |
+
<path>
|
| 1126 |
+
<move x="47.32" y="70.75" />
|
| 1127 |
+
<line x="64.1" y="70.75" />
|
| 1128 |
+
</path>
|
| 1129 |
+
<fillstroke />
|
| 1130 |
+
<stroke />
|
| 1131 |
+
<path>
|
| 1132 |
+
<move x="47.32" y="66.35" />
|
| 1133 |
+
<line x="64.1" y="66.35" />
|
| 1134 |
+
</path>
|
| 1135 |
+
<fillstroke />
|
| 1136 |
+
<stroke />
|
| 1137 |
+
<path>
|
| 1138 |
+
<move x="47.32" y="61.94" />
|
| 1139 |
+
<line x="64.1" y="61.94" />
|
| 1140 |
+
</path>
|
| 1141 |
+
<fillstroke />
|
| 1142 |
+
<stroke />
|
| 1143 |
+
<path>
|
| 1144 |
+
<move x="47.32" y="57.53" />
|
| 1145 |
+
<line x="64.1" y="57.53" />
|
| 1146 |
+
</path>
|
| 1147 |
+
<fillstroke />
|
| 1148 |
+
<stroke />
|
| 1149 |
+
<path>
|
| 1150 |
+
<move x="47.32" y="128.05" />
|
| 1151 |
+
<line x="64.1" y="128.05" />
|
| 1152 |
+
</path>
|
| 1153 |
+
<fillstroke />
|
| 1154 |
+
<stroke />
|
| 1155 |
+
<path>
|
| 1156 |
+
<move x="47.32" y="123.64" />
|
| 1157 |
+
<line x="64.1" y="123.64" />
|
| 1158 |
+
</path>
|
| 1159 |
+
<fillstroke />
|
| 1160 |
+
<stroke />
|
| 1161 |
+
<rect x="128.4" y="39.02" w="9.32" h="93.43" />
|
| 1162 |
+
<fillstroke />
|
| 1163 |
+
<stroke />
|
| 1164 |
+
<path>
|
| 1165 |
+
<move x="113.49" y="125.4" />
|
| 1166 |
+
<line x="130.27" y="125.4" />
|
| 1167 |
+
</path>
|
| 1168 |
+
<fillstroke />
|
| 1169 |
+
<stroke />
|
| 1170 |
+
<path>
|
| 1171 |
+
<move x="113.49" y="120.99" />
|
| 1172 |
+
<line x="130.27" y="120.99" />
|
| 1173 |
+
</path>
|
| 1174 |
+
<fillstroke />
|
| 1175 |
+
<stroke />
|
| 1176 |
+
<path>
|
| 1177 |
+
<move x="113.49" y="116.59" />
|
| 1178 |
+
<line x="130.27" y="116.59" />
|
| 1179 |
+
</path>
|
| 1180 |
+
<fillstroke />
|
| 1181 |
+
<stroke />
|
| 1182 |
+
<path>
|
| 1183 |
+
<move x="113.49" y="112.18" />
|
| 1184 |
+
<line x="130.27" y="112.18" />
|
| 1185 |
+
</path>
|
| 1186 |
+
<fillstroke />
|
| 1187 |
+
<stroke />
|
| 1188 |
+
<path>
|
| 1189 |
+
<move x="113.49" y="107.77" />
|
| 1190 |
+
<line x="130.27" y="107.77" />
|
| 1191 |
+
</path>
|
| 1192 |
+
<fillstroke />
|
| 1193 |
+
<stroke />
|
| 1194 |
+
<path>
|
| 1195 |
+
<move x="113.49" y="103.37" />
|
| 1196 |
+
<line x="130.27" y="103.37" />
|
| 1197 |
+
</path>
|
| 1198 |
+
<fillstroke />
|
| 1199 |
+
<stroke />
|
| 1200 |
+
<path>
|
| 1201 |
+
<move x="113.49" y="98.96" />
|
| 1202 |
+
<line x="130.27" y="98.96" />
|
| 1203 |
+
</path>
|
| 1204 |
+
<fillstroke />
|
| 1205 |
+
<stroke />
|
| 1206 |
+
<path>
|
| 1207 |
+
<move x="113.49" y="94.55" />
|
| 1208 |
+
<line x="130.27" y="94.55" />
|
| 1209 |
+
</path>
|
| 1210 |
+
<fillstroke />
|
| 1211 |
+
<stroke />
|
| 1212 |
+
<path>
|
| 1213 |
+
<move x="113.49" y="90.14" />
|
| 1214 |
+
<line x="130.27" y="90.14" />
|
| 1215 |
+
</path>
|
| 1216 |
+
<fillstroke />
|
| 1217 |
+
<stroke />
|
| 1218 |
+
<path>
|
| 1219 |
+
<move x="113.49" y="85.74" />
|
| 1220 |
+
<line x="130.27" y="85.74" />
|
| 1221 |
+
</path>
|
| 1222 |
+
<fillstroke />
|
| 1223 |
+
<stroke />
|
| 1224 |
+
<path>
|
| 1225 |
+
<move x="113.49" y="81.33" />
|
| 1226 |
+
<line x="130.27" y="81.33" />
|
| 1227 |
+
</path>
|
| 1228 |
+
<fillstroke />
|
| 1229 |
+
<stroke />
|
| 1230 |
+
<path>
|
| 1231 |
+
<move x="113.49" y="76.92" />
|
| 1232 |
+
<line x="130.27" y="76.92" />
|
| 1233 |
+
</path>
|
| 1234 |
+
<fillstroke />
|
| 1235 |
+
<stroke />
|
| 1236 |
+
<path>
|
| 1237 |
+
<move x="113.49" y="72.52" />
|
| 1238 |
+
<line x="130.27" y="72.52" />
|
| 1239 |
+
</path>
|
| 1240 |
+
<fillstroke />
|
| 1241 |
+
<stroke />
|
| 1242 |
+
<path>
|
| 1243 |
+
<move x="113.49" y="68.11" />
|
| 1244 |
+
<line x="130.27" y="68.11" />
|
| 1245 |
+
</path>
|
| 1246 |
+
<fillstroke />
|
| 1247 |
+
<stroke />
|
| 1248 |
+
<path>
|
| 1249 |
+
<move x="113.49" y="63.7" />
|
| 1250 |
+
<line x="130.27" y="63.7" />
|
| 1251 |
+
</path>
|
| 1252 |
+
<fillstroke />
|
| 1253 |
+
<stroke />
|
| 1254 |
+
<path>
|
| 1255 |
+
<move x="113.49" y="59.29" />
|
| 1256 |
+
<line x="130.27" y="59.29" />
|
| 1257 |
+
</path>
|
| 1258 |
+
<fillstroke />
|
| 1259 |
+
<stroke />
|
| 1260 |
+
<path>
|
| 1261 |
+
<move x="113.49" y="54.89" />
|
| 1262 |
+
<line x="130.27" y="54.89" />
|
| 1263 |
+
</path>
|
| 1264 |
+
<fillstroke />
|
| 1265 |
+
<stroke />
|
| 1266 |
+
<path>
|
| 1267 |
+
<move x="134.92" y="119.23" />
|
| 1268 |
+
<line x="151.7" y="119.23" />
|
| 1269 |
+
</path>
|
| 1270 |
+
<fillstroke />
|
| 1271 |
+
<stroke />
|
| 1272 |
+
<path>
|
| 1273 |
+
<move x="134.92" y="114.82" />
|
| 1274 |
+
<line x="151.7" y="114.82" />
|
| 1275 |
+
</path>
|
| 1276 |
+
<fillstroke />
|
| 1277 |
+
<stroke />
|
| 1278 |
+
<path>
|
| 1279 |
+
<move x="134.92" y="110.42" />
|
| 1280 |
+
<line x="151.7" y="110.42" />
|
| 1281 |
+
</path>
|
| 1282 |
+
<fillstroke />
|
| 1283 |
+
<stroke />
|
| 1284 |
+
<path>
|
| 1285 |
+
<move x="134.92" y="106.01" />
|
| 1286 |
+
<line x="151.7" y="106.01" />
|
| 1287 |
+
</path>
|
| 1288 |
+
<fillstroke />
|
| 1289 |
+
<stroke />
|
| 1290 |
+
<path>
|
| 1291 |
+
<move x="134.92" y="101.6" />
|
| 1292 |
+
<line x="151.7" y="101.6" />
|
| 1293 |
+
</path>
|
| 1294 |
+
<fillstroke />
|
| 1295 |
+
<stroke />
|
| 1296 |
+
<path>
|
| 1297 |
+
<move x="134.92" y="97.2" />
|
| 1298 |
+
<line x="151.7" y="97.2" />
|
| 1299 |
+
</path>
|
| 1300 |
+
<fillstroke />
|
| 1301 |
+
<stroke />
|
| 1302 |
+
<path>
|
| 1303 |
+
<move x="134.92" y="92.79" />
|
| 1304 |
+
<line x="151.7" y="92.79" />
|
| 1305 |
+
</path>
|
| 1306 |
+
<fillstroke />
|
| 1307 |
+
<stroke />
|
| 1308 |
+
<path>
|
| 1309 |
+
<move x="134.92" y="88.38" />
|
| 1310 |
+
<line x="151.7" y="88.38" />
|
| 1311 |
+
</path>
|
| 1312 |
+
<fillstroke />
|
| 1313 |
+
<stroke />
|
| 1314 |
+
<path>
|
| 1315 |
+
<move x="134.92" y="83.97" />
|
| 1316 |
+
<line x="151.7" y="83.97" />
|
| 1317 |
+
</path>
|
| 1318 |
+
<fillstroke />
|
| 1319 |
+
<stroke />
|
| 1320 |
+
<path>
|
| 1321 |
+
<move x="134.92" y="79.57" />
|
| 1322 |
+
<line x="151.7" y="79.57" />
|
| 1323 |
+
</path>
|
| 1324 |
+
<fillstroke />
|
| 1325 |
+
<stroke />
|
| 1326 |
+
<path>
|
| 1327 |
+
<move x="134.92" y="75.16" />
|
| 1328 |
+
<line x="151.7" y="75.16" />
|
| 1329 |
+
</path>
|
| 1330 |
+
<fillstroke />
|
| 1331 |
+
<stroke />
|
| 1332 |
+
<path>
|
| 1333 |
+
<move x="134.92" y="70.75" />
|
| 1334 |
+
<line x="151.7" y="70.75" />
|
| 1335 |
+
</path>
|
| 1336 |
+
<fillstroke />
|
| 1337 |
+
<stroke />
|
| 1338 |
+
<path>
|
| 1339 |
+
<move x="134.92" y="66.35" />
|
| 1340 |
+
<line x="151.7" y="66.35" />
|
| 1341 |
+
</path>
|
| 1342 |
+
<fillstroke />
|
| 1343 |
+
<stroke />
|
| 1344 |
+
<path>
|
| 1345 |
+
<move x="134.92" y="61.94" />
|
| 1346 |
+
<line x="151.7" y="61.94" />
|
| 1347 |
+
</path>
|
| 1348 |
+
<fillstroke />
|
| 1349 |
+
<stroke />
|
| 1350 |
+
<path>
|
| 1351 |
+
<move x="134.92" y="57.53" />
|
| 1352 |
+
<line x="151.7" y="57.53" />
|
| 1353 |
+
</path>
|
| 1354 |
+
<fillstroke />
|
| 1355 |
+
<stroke />
|
| 1356 |
+
<path>
|
| 1357 |
+
<move x="134.92" y="128.05" />
|
| 1358 |
+
<line x="151.7" y="128.05" />
|
| 1359 |
+
</path>
|
| 1360 |
+
<fillstroke />
|
| 1361 |
+
<stroke />
|
| 1362 |
+
<path>
|
| 1363 |
+
<move x="134.92" y="123.64" />
|
| 1364 |
+
<line x="151.7" y="123.64" />
|
| 1365 |
+
</path>
|
| 1366 |
+
<fillstroke />
|
| 1367 |
+
<stroke />
|
| 1368 |
+
</foreground>
|
| 1369 |
+
</shape><shape h="116.0" w="114.0" aspect="variable" strokewidth="inherit" name="MachineFinalCleaningStubEnd" displayName="MachineFinalCleaningStubEnd">
|
| 1370 |
+
<foreground>
|
| 1371 |
+
<rect x="0" y="0" w="114" h="116" />
|
| 1372 |
+
<fillstroke />
|
| 1373 |
+
<stroke />
|
| 1374 |
+
<path>
|
| 1375 |
+
<move x="8.63" y="99.06" />
|
| 1376 |
+
<line x="13.0" y="106.0" />
|
| 1377 |
+
<line x="26.0" y="106.0" />
|
| 1378 |
+
<line x="26.0" y="21.0" />
|
| 1379 |
+
<line x="26.0" y="31.0" />
|
| 1380 |
+
<line x="28.0" y="39.0" />
|
| 1381 |
+
<line x="31.0" y="39.0" />
|
| 1382 |
+
<line x="32.0" y="32.0" />
|
| 1383 |
+
<line x="34.0" y="39.0" />
|
| 1384 |
+
<line x="36.0" y="39.0" />
|
| 1385 |
+
<line x="39.0" y="32.0" />
|
| 1386 |
+
<line x="39.0" y="24.0" />
|
| 1387 |
+
<line x="25.0" y="10.0" />
|
| 1388 |
+
<line x="14.0" y="10.0" />
|
| 1389 |
+
<line x="14.0" y="99.0" />
|
| 1390 |
+
<line x="8.52" y="98.95" />
|
| 1391 |
+
<close />
|
| 1392 |
+
</path>
|
| 1393 |
+
<stroke />
|
| 1394 |
+
<path>
|
| 1395 |
+
<move x="104.11" y="99.06" />
|
| 1396 |
+
<line x="101.0" y="106.0" />
|
| 1397 |
+
<line x="87.0" y="106.0" />
|
| 1398 |
+
<line x="87.0" y="21.0" />
|
| 1399 |
+
<line x="87.0" y="32.0" />
|
| 1400 |
+
<line x="85.0" y="39.0" />
|
| 1401 |
+
<line x="83.0" y="39.0" />
|
| 1402 |
+
<line x="81.0" y="33.0" />
|
| 1403 |
+
<line x="79.0" y="39.0" />
|
| 1404 |
+
<line x="77.0" y="39.0" />
|
| 1405 |
+
<line x="74.0" y="33.0" />
|
| 1406 |
+
<line x="74.0" y="25.0" />
|
| 1407 |
+
<line x="88.0" y="10.0" />
|
| 1408 |
+
<line x="99.0" y="10.0" />
|
| 1409 |
+
<line x="99.0" y="99.0" />
|
| 1410 |
+
<line x="104.0" y="98.95" />
|
| 1411 |
+
<close />
|
| 1412 |
+
</path>
|
| 1413 |
+
<stroke />
|
| 1414 |
+
<roundrect arcsize="40" x="41.21" y="91.1" w="30.59" h="5" />
|
| 1415 |
+
<stroke />
|
| 1416 |
+
<ellipse x="33.0" y="73.0" w="3.9999999999999996" h="2.9999999999999996" />
|
| 1417 |
+
<stroke />
|
| 1418 |
+
<ellipse x="33.0" y="90.0" w="3.9999999999999996" h="2.9999999999999996" />
|
| 1419 |
+
<stroke />
|
| 1420 |
+
<ellipse x="76.0" y="73.0" w="3.9999999999999996" h="2.9999999999999996" />
|
| 1421 |
+
<stroke />
|
| 1422 |
+
<ellipse x="76.0" y="90.0" w="3.9999999999999996" h="2.9999999999999996" />
|
| 1423 |
+
<stroke />
|
| 1424 |
+
<path>
|
| 1425 |
+
<move x="37.0" y="74.5" />
|
| 1426 |
+
<line x="48.0" y="74.5" />
|
| 1427 |
+
</path>
|
| 1428 |
+
<stroke />
|
| 1429 |
+
<path>
|
| 1430 |
+
<move x="37.0" y="91.45" />
|
| 1431 |
+
<line x="48.57" y="91.45" />
|
| 1432 |
+
</path>
|
| 1433 |
+
<stroke />
|
| 1434 |
+
<path>
|
| 1435 |
+
<move x="37.35096464368121" y="91.12723079889126" />
|
| 1436 |
+
<line x="48.06903535631879" y="88.65276920110874" />
|
| 1437 |
+
</path>
|
| 1438 |
+
<stroke />
|
| 1439 |
+
<path>
|
| 1440 |
+
<move x="37.384663756410546" y="91.18467039993075" />
|
| 1441 |
+
<line x="46.395336243589455" y="84.87532960006925" />
|
| 1442 |
+
</path>
|
| 1443 |
+
<stroke />
|
| 1444 |
+
<path>
|
| 1445 |
+
<move x="76.30000000000001" y="75.11" />
|
| 1446 |
+
<line x="64.73" y="75.11" />
|
| 1447 |
+
</path>
|
| 1448 |
+
<stroke />
|
| 1449 |
+
<path>
|
| 1450 |
+
<move x="75.92903535631879" y="75.43276920110874" />
|
| 1451 |
+
<line x="65.2109646436812" y="77.90723079889126" />
|
| 1452 |
+
</path>
|
| 1453 |
+
<stroke />
|
| 1454 |
+
<path>
|
| 1455 |
+
<move x="75.89533624358945" y="75.37532960006925" />
|
| 1456 |
+
<line x="66.88466375641055" y="81.68467039993075" />
|
| 1457 |
+
</path>
|
| 1458 |
+
<stroke />
|
| 1459 |
+
<path>
|
| 1460 |
+
<move x="75.46469881599037" y="91.54527180210906" />
|
| 1461 |
+
<line x="65.98710966356674" y="84.90899243352746" />
|
| 1462 |
+
</path>
|
| 1463 |
+
<stroke />
|
| 1464 |
+
<path>
|
| 1465 |
+
<move x="74.99951120011734" y="91.60033626378753" />
|
| 1466 |
+
<line x="64.80048879988267" y="87.47966373621249" />
|
| 1467 |
+
</path>
|
| 1468 |
+
<stroke />
|
| 1469 |
+
<path>
|
| 1470 |
+
<move x="76.0" y="91.54" />
|
| 1471 |
+
<line x="64.0" y="91.54" />
|
| 1472 |
+
</path>
|
| 1473 |
+
<stroke />
|
| 1474 |
+
<path>
|
| 1475 |
+
<move x="37.000488799882675" y="74.43966373621248" />
|
| 1476 |
+
<line x="47.19951120011733" y="78.56033626378752" />
|
| 1477 |
+
</path>
|
| 1478 |
+
<stroke />
|
| 1479 |
+
<path>
|
| 1480 |
+
<move x="36.994663756410546" y="74.82532960006925" />
|
| 1481 |
+
<line x="46.005336243589454" y="81.13467039993076" />
|
| 1482 |
+
</path>
|
| 1483 |
+
<stroke />
|
| 1484 |
+
<path>
|
| 1485 |
+
<move x="54.47" y="28.0" />
|
| 1486 |
+
<line x="59.0" y="28.0" />
|
| 1487 |
+
<line x="59.0" y="76.0" />
|
| 1488 |
+
<line x="69.0" y="76.0" />
|
| 1489 |
+
<line x="69.0" y="92.0" />
|
| 1490 |
+
<line x="65.0" y="92.0" />
|
| 1491 |
+
<line x="65.0" y="81.0" />
|
| 1492 |
+
<line x="59.0" y="81.0" />
|
| 1493 |
+
<line x="59.0" y="92.0" />
|
| 1494 |
+
<line x="54.0" y="92.0" />
|
| 1495 |
+
<line x="54.0" y="81.0" />
|
| 1496 |
+
<line x="48.0" y="81.0" />
|
| 1497 |
+
<line x="48.0" y="92.0" />
|
| 1498 |
+
<line x="44.0" y="92.0" />
|
| 1499 |
+
<line x="44.0" y="76.0" />
|
| 1500 |
+
<line x="54.0" y="76.0" />
|
| 1501 |
+
<line x="54.0" y="28.0" />
|
| 1502 |
+
<close />
|
| 1503 |
+
</path>
|
| 1504 |
+
<stroke />
|
| 1505 |
+
</foreground>
|
| 1506 |
+
</shape><shape h="172.0" w="107.0" aspect="variable" strokewidth="inherit" name="MachineInductionDryingNipple" displayName="MachineInductionDryingNipple">
|
| 1507 |
+
<foreground>
|
| 1508 |
+
<rect x="0" y="0" w="107" h="172" />
|
| 1509 |
+
<fillstroke />
|
| 1510 |
+
<stroke />
|
| 1511 |
+
<path>
|
| 1512 |
+
<move x="18.82" y="150.72" />
|
| 1513 |
+
<line x="26.0" y="163.5" />
|
| 1514 |
+
<line x="31.0" y="158.5" />
|
| 1515 |
+
<line x="39.0" y="170.0" />
|
| 1516 |
+
</path>
|
| 1517 |
+
<stroke />
|
| 1518 |
+
<path>
|
| 1519 |
+
<move x="51.0" y="150.0" />
|
| 1520 |
+
<line x="58.58" y="163.5" />
|
| 1521 |
+
<line x="63.58" y="158.5" />
|
| 1522 |
+
<line x="71.58" y="170.0" />
|
| 1523 |
+
</path>
|
| 1524 |
+
<stroke />
|
| 1525 |
+
<path>
|
| 1526 |
+
<move x="83.4" y="150.66" />
|
| 1527 |
+
<line x="90.58" y="163.5" />
|
| 1528 |
+
<line x="95.58" y="158.5" />
|
| 1529 |
+
<line x="103.58" y="170.0" />
|
| 1530 |
+
</path>
|
| 1531 |
+
<stroke />
|
| 1532 |
+
<ellipse x="76.0" y="144.0" w="10.999999999999998" h="6.999999999999999" />
|
| 1533 |
+
<stroke />
|
| 1534 |
+
<ellipse x="42.0" y="144.0" w="10.999999999999998" h="6.999999999999999" />
|
| 1535 |
+
<fillstroke />
|
| 1536 |
+
<stroke />
|
| 1537 |
+
<ellipse x="11.0" y="144.0" w="10.999999999999998" h="6.999999999999999" />
|
| 1538 |
+
<stroke />
|
| 1539 |
+
<path>
|
| 1540 |
+
<move x="42.89" y="4.04" />
|
| 1541 |
+
<line x="43.0" y="99.0" />
|
| 1542 |
+
<line x="12.0" y="99.0" />
|
| 1543 |
+
<line x="12.0" y="137.0" />
|
| 1544 |
+
<line x="24.0" y="137.0" />
|
| 1545 |
+
<line x="24.0" y="111.0" />
|
| 1546 |
+
<line x="43.0" y="111.0" />
|
| 1547 |
+
<line x="43.0" y="138.0" />
|
| 1548 |
+
<line x="55.0" y="138.0" />
|
| 1549 |
+
<line x="55.0" y="111.0" />
|
| 1550 |
+
<line x="74.0" y="111.0" />
|
| 1551 |
+
<line x="74.0" y="137.0" />
|
| 1552 |
+
<line x="86.0" y="137.0" />
|
| 1553 |
+
<line x="86.0" y="99.0" />
|
| 1554 |
+
<line x="55.0" y="99.0" />
|
| 1555 |
+
<line x="55.0" y="4.0" />
|
| 1556 |
+
<line x="43.0" y="4.0" />
|
| 1557 |
+
<close />
|
| 1558 |
+
</path>
|
| 1559 |
+
<stroke />
|
| 1560 |
+
</foreground>
|
| 1561 |
+
</shape><shape h="110.0" w="119.0" aspect="variable" strokewidth="inherit" name="MachineMovablePouringCrucible" displayName="MachineMovablePouringCrucible"><foreground><rect x="0" y="0" w="119" h="110" /><fillstroke /><stroke /><rect x="13.44" y="26.19" w="59.5" h="59.37" /><fillstroke /><stroke /><path><move x="94.57" y="26.1" /><curve x1="87.01" y1="46.56" x2="90.85" y2="54.71" x3="90.85" y3="54.71" /><curve x1="94.69" y1="62.86" x2="98.85" y2="55.0" x3="98.85" y3="55.0" /><curve x1="103.01" y1="47.14" x2="94.57" y2="26.24" x3="94.57" y3="26.24" /></path><stroke /><path><move x="73.0" y="35.0" /><line x="92.0" y="35.0" /></path><stroke /><path><move x="73.1" y="73.07" /><line x="106.0" y="73.0" /><line x="106.0" y="35.0" /><line x="98.0" y="35.0" /></path><stroke /></foreground></shape><shape h="116.0" w="114.0" aspect="variable" strokewidth="inherit" name="Machine_Cleaning_Nipple" displayName="Machine_Cleaning_Nipple"><foreground><rect x="45.5" y="76.5" w="25" h="4.77" /><fillstroke /><stroke /><rect x="45.5" y="81.27" w="4.05" h="10.34" /><fillstroke /><stroke /><rect x="66.5" y="81" w="4" h="10.6" /><fillstroke /><stroke /><rect x="55.97" y="28" w="4.05" h="64" /><fillstroke /><stroke /><rect x="46" y="78.48" w="3.1" h="10.68" /><fillstroke /><stroke /><rect x="66.92" y="77" w="3.1" h="10.68" /><fillstroke /><stroke /><path><move x="63.370000000000005" y="76.99" /><line x="63.370000000000005" y="80.75999999999999" /><line x="53.03" y="80.76" /><line x="53.03" y="76.99" /><close /></path><fillstroke /><stroke /><rect x="56.46" y="73" w="3.1" h="10.68" /><fillstroke /><stroke /><rect x="0" y="0" w="114" h="116" /><fillstroke /><stroke /><path><move x="9.63" y="99.06" /><line x="14.0" y="106.0" /><line x="27.0" y="106.0" /><line x="27.0" y="21.0" /><line x="27.0" y="31.0" /><line x="29.0" y="39.0" /><line x="32.0" y="39.0" /><line x="33.0" y="32.0" /><line x="35.0" y="39.0" /><line x="37.0" y="39.0" /><line x="40.0" y="32.0" /><line x="40.0" y="24.0" /><line x="26.0" y="10.0" /><line x="15.0" y="10.0" /><line x="15.0" y="99.0" /><line x="9.52" y="98.95" /></path><fillstroke /><stroke /><path><move x="105.11" y="99.06" /><line x="102.0" y="106.0" /><line x="88.0" y="106.0" /><line x="88.0" y="21.0" /><line x="88.0" y="32.0" /><line x="86.0" y="39.0" /><line x="84.0" y="39.0" /><line x="82.0" y="33.0" /><line x="80.0" y="39.0" /><line x="78.0" y="39.0" /><line x="75.0" y="33.0" /><line x="75.0" y="25.0" /><line x="89.0" y="10.0" /><line x="100.0" y="10.0" /><line x="100.0" y="99.0" /><line x="105.0" y="98.95" /></path><fillstroke /><stroke /><ellipse x="34.0" y="73.0" w="4.0" h="3.0" /><fillstroke /><stroke /><ellipse x="34.0" y="90.0" w="4.0" h="3.0" /><fillstroke /><stroke /><ellipse x="77.0" y="73.0" w="4.0" h="3.0" /><fillstroke /><stroke /><ellipse x="77.0" y="90.0" w="4.0" h="3.0" /><fillstroke /><stroke /><path><move x="38.0" y="74.5" /><line x="49.0" y="74.5" /></path><fillstroke /><stroke /><path><move x="38.0" y="91.45" /><line x="49.57" y="91.45" /></path><fillstroke /><stroke /><path><move x="38.35096464368121" y="91.12723079889126" /><line x="49.06903535631879" y="88.65276920110874" /></path><fillstroke /><stroke /><path><move x="38.384663756410546" y="91.18467039993075" /><line x="47.395336243589455" y="84.87532960006925" /></path><fillstroke /><stroke /><path><move x="77.30000000000001" y="75.11" /><line x="65.73" y="75.11" /></path><fillstroke /><stroke /><path><move x="76.92903535631879" y="75.43276920110874" /><line x="66.2109646436812" y="77.90723079889126" /></path><fillstroke /><stroke /><path><move x="76.89533624358945" y="75.37532960006925" /><line x="67.88466375641055" y="81.68467039993075" /></path><fillstroke /><stroke /><path><move x="76.46469881599037" y="91.54527180210906" /><line x="66.98710966356674" y="84.90899243352746" /></path><fillstroke /><stroke /><path><move x="75.99951120011734" y="91.60033626378753" /><line x="65.80048879988267" y="87.47966373621249" /></path><fillstroke /><stroke /><path><move x="77.0" y="91.54" /><line x="65.0" y="91.54" /></path><fillstroke /><stroke /><path><move x="37.994663756410546" y="74.82532960006925" /><line x="47.005336243589454" y="81.13467039993076" /></path><fillstroke /><stroke /><path><move x="38.000488799882675" y="74.43966373621248" /><line x="48.19951120011733" y="78.56033626378752" /></path><fillstroke /><stroke /></foreground></shape><shape h="90.0" w="84.0" aspect="variable" strokewidth="inherit" name="magnet" displayName="magnet">
|
| 1562 |
+
<foreground>
|
| 1563 |
+
<rect x="0" y="0" w="83.08" h="90" />
|
| 1564 |
+
<fillstroke />
|
| 1565 |
+
<stroke />
|
| 1566 |
+
|
| 1567 |
+
<path>
|
| 1568 |
+
<move x="12.69" y="73.84" />
|
| 1569 |
+
<line x="12.69" y="40.38" />
|
| 1570 |
+
<arc sweep-flag="1" rx="22.5" ry="22.5" x="71.54" y="40.38" />
|
| 1571 |
+
<line x="71.54" y="73.84" />
|
| 1572 |
+
<line x="60" y="73.84" />
|
| 1573 |
+
<line x="60" y="40.38" />
|
| 1574 |
+
<arc rx="17.9" ry="17.9" x="24.23" y="40.38" />
|
| 1575 |
+
<line x="24.23" y="73.84" />
|
| 1576 |
+
|
| 1577 |
+
<close />
|
| 1578 |
+
</path>
|
| 1579 |
+
<fillstroke />
|
| 1580 |
+
<stroke />
|
| 1581 |
+
|
| 1582 |
+
</foreground>
|
| 1583 |
+
</shape><shape h="84.0" w="70.0" aspect="variable" strokewidth="inherit" name="MB" displayName="MB">
|
| 1584 |
+
<foreground>
|
| 1585 |
+
|
| 1586 |
+
|
| 1587 |
+
<path>
|
| 1588 |
+
<move x="7.0" y="0.43" />
|
| 1589 |
+
<line x="7.0" y="82.43" />
|
| 1590 |
+
<line x="58.0" y="82.43" />
|
| 1591 |
+
<line x="58.0" y="62.0" />
|
| 1592 |
+
</path>
|
| 1593 |
+
<stroke />
|
| 1594 |
+
|
| 1595 |
+
|
| 1596 |
+
<path>
|
| 1597 |
+
<move x="58.0" y="63.0" />
|
| 1598 |
+
<curve x1="58.0" y1="61.0" x2="60.0" y2="61.0" x3="62.0" y3="61.0" />
|
| 1599 |
+
<curve x1="64.0" y1="61.0" x2="66.0" y2="61.0" x3="65.5" y3="63.0" />
|
| 1600 |
+
<curve x1="65.0" y1="65.0" x2="64.5" y2="66.0" x3="63.0" y3="67.0" />
|
| 1601 |
+
<curve x1="61.0" y1="68.5" x2="58.0" y2="70.0" x3="55.0" y3="69.0" />
|
| 1602 |
+
<curve x1="52.0" y1="68.0" x2="51.0" y2="66.0" x3="50.5" y3="64.0" />
|
| 1603 |
+
<curve x1="50.0" y1="62.0" x2="50.5" y2="60.0" x3="51.5" y3="57.5" />
|
| 1604 |
+
<curve x1="53.0" y1="55.0" x2="55.5" y2="55.0" x3="58.0" y3="55.0" />
|
| 1605 |
+
<curve x1="58.13" y1="53.46" x2="58.13" x3="58.13" y2="53.46" y3="53.46" />
|
| 1606 |
+
</path>
|
| 1607 |
+
<stroke />
|
| 1608 |
+
|
| 1609 |
+
|
| 1610 |
+
<path>
|
| 1611 |
+
<move x="58.0" y="0.0" />
|
| 1612 |
+
<line x="58.0" y="54.0" />
|
| 1613 |
+
</path>
|
| 1614 |
+
<stroke />
|
| 1615 |
+
|
| 1616 |
+
|
| 1617 |
+
<rect x="0" y="37.5" w="14" h="14" />
|
| 1618 |
+
<fillstroke />
|
| 1619 |
+
<stroke />
|
| 1620 |
+
|
| 1621 |
+
<path>
|
| 1622 |
+
<move x="7.0" y="14.33" />
|
| 1623 |
+
<line x="16.86" y="14.29" />
|
| 1624 |
+
<line x="16.88" y="0.0" />
|
| 1625 |
+
</path>
|
| 1626 |
+
<stroke />
|
| 1627 |
+
|
| 1628 |
+
|
| 1629 |
+
<path>
|
| 1630 |
+
<move x="58.0" y="14.33" />
|
| 1631 |
+
<line x="67.86" y="14.29" />
|
| 1632 |
+
<line x="67.88" y="0.0" />
|
| 1633 |
+
</path>
|
| 1634 |
+
<stroke />
|
| 1635 |
+
</foreground>
|
| 1636 |
+
</shape><shape h="48.0" w="154.0" aspect="variable" strokewidth="inherit" name="MIKA" displayName="MIKA"><foreground><roundrect arcsize="5.85" x="5" y="4.64" w="141" h="39" /><fillstroke /><stroke /><rect x="0" y="1" w="15" h="47" /><fillstroke /><stroke /><rect x="58" y="2" w="5" h="45" /><fillstroke /><stroke /><rect x="58" y="7" w="5" h="4" /><fillstroke /><stroke /><rect x="58" y="16" w="5" h="4" /><fillstroke /><stroke /><rect x="58" y="25" w="5" h="4" /><fillstroke /><stroke /><rect x="58" y="34" w="5" h="4" /><fillstroke /><stroke /><rect x="58" y="43" w="5" h="4" /><fillstroke /><stroke /><rect x="139" y="0" w="15" h="48" /><fillstroke /><stroke /></foreground></shape><shape h="71.0" w="90.0" aspect="variable" strokewidth="inherit" name="mill" displayName="mill">
|
| 1637 |
+
<foreground>
|
| 1638 |
+
|
| 1639 |
+
|
| 1640 |
+
<roundrect arcsize="5" x="0" y="17" w="90" h="38" />
|
| 1641 |
+
<fillstroke />
|
| 1642 |
+
<stroke />
|
| 1643 |
+
|
| 1644 |
+
|
| 1645 |
+
<roundrect arcsize="6.27" x="14" y="7.5" w="71" h="57" />
|
| 1646 |
+
<fillstroke />
|
| 1647 |
+
<stroke />
|
| 1648 |
+
|
| 1649 |
+
|
| 1650 |
+
<rect x="70" y="0.5" w="11" h="71" />
|
| 1651 |
+
<fillstroke />
|
| 1652 |
+
<stroke />
|
| 1653 |
+
</foreground>
|
| 1654 |
+
</shape><shape h="222.0" w="301.0" aspect="variable" strokewidth="inherit" name="mixer" displayName="mixer"><foreground><path><move x="40.18" y="0.0" /><line x="260.18" y="0.0" /><line x="300.18" y="32.0" /><line x="300.18" y="76.0" /><line x="0.18" y="76.0" /><line x="0.18" y="32.0" /><close /></path><fillstroke /><stroke /><rect x="16.88" y="75.9" w="266.59" h="92.32" /><fillstroke /><stroke /><rect x="1.9" y="163.43" w="296.55" h="58" /><fillstroke /><stroke /></foreground></shape><shape h="101.0" w="48.0" aspect="variable" strokewidth="inherit" name="mixer_2" displayName="mixer_2"><foreground><rect x="0" y="10.11" w="48" h="79.78" /><fillstroke /><stroke /><ellipse x="0.0" y="-0.0023595505617990398" w="48.0" h="20.224719101123597" /><fillstroke /><stroke /><ellipse x="0.0" y="79.7776404494382" w="48.0" h="20.224719101123597" /><fillstroke /><stroke /><rect x="0" y="10.11" w="48" h="79.78" /><fillstroke /><stroke /><path><move x="23.999999999999996" y="0.0" /><line x="24.000000000000004" y="76.4" /></path><fillstroke /><stroke /><path><move x="11.76" y="70.79" /><line x="24.0" y="75.84" /><line x="11.76" y="80.9" /><close /><move x="36.24" y="70.79" /><line x="24.0" y="75.84" /><line x="36.24" y="80.9" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="69.0" w="47.0" aspect="variable" strokewidth="inherit" name="PKN" displayName="PKN"><foreground><rect x="0" y="18.83" w="47" h="39.17" /><fillstroke /><stroke /><path><move x="0.0" y="18.83" /><line x="3.61" y="7.0" /><line x="43.19" y="7.0" /><line x="46.8" y="18.83" /><close /></path><fillstroke /><stroke /><path><move x="46.81" y="58.0" /><line x="42.2" y="68.6" /><line x="4.810000000000002" y="68.6" /><line x="0.20000000000000284" y="58.0" /><close /></path><fillstroke /><stroke /><rect x="15" y="1.77" w="16" h="5.23" /><fillstroke /><stroke /></foreground></shape><shape h="120.0" w="117.0" aspect="variable" strokewidth="inherit" name="PressButtStripper" displayName="PressButtStripper">
|
| 1655 |
+
<foreground>
|
| 1656 |
+
<rect x="0" y="0" w="116.32" h="120" />
|
| 1657 |
+
<fillstroke />
|
| 1658 |
+
<stroke />
|
| 1659 |
+
<rect x="34.41" y="26.5" w="41" h="59" />
|
| 1660 |
+
<fillstroke />
|
| 1661 |
+
<stroke />
|
| 1662 |
+
<rect x="7.16" y="30.5" w="24" h="51" />
|
| 1663 |
+
<fillstroke />
|
| 1664 |
+
<stroke />
|
| 1665 |
+
<rect x="7.16" y="49.5" w="11.5" h="14" />
|
| 1666 |
+
<fillstroke />
|
| 1667 |
+
<stroke />
|
| 1668 |
+
|
| 1669 |
+
<path>
|
| 1670 |
+
<move x="79.16" y="12.5" />
|
| 1671 |
+
<line x="72.16" y="12.5" />
|
| 1672 |
+
<line x="69.16" y="19.5" />
|
| 1673 |
+
<line x="38.16" y="23.5" />
|
| 1674 |
+
<line x="79.16" y="23.5" />
|
| 1675 |
+
</path>
|
| 1676 |
+
<fillstroke />
|
| 1677 |
+
<stroke />
|
| 1678 |
+
<path>
|
| 1679 |
+
<move x="79.16" y="88.5" />
|
| 1680 |
+
<line x="72.16" y="88.5" />
|
| 1681 |
+
<line x="38.16" y="88.5" />
|
| 1682 |
+
<line x="70.16" y="93.5" />
|
| 1683 |
+
<line x="72.16" y="99.5" />
|
| 1684 |
+
<line x="79.16" y="99.5" />
|
| 1685 |
+
</path>
|
| 1686 |
+
<fillstroke />
|
| 1687 |
+
<stroke />
|
| 1688 |
+
<rect x="79.16" y="7.5" w="24" h="99" />
|
| 1689 |
+
<fillstroke />
|
| 1690 |
+
<stroke />
|
| 1691 |
+
<rect x="53.47" y="62.5" w="2.88" h="6" />
|
| 1692 |
+
<fillstroke />
|
| 1693 |
+
<stroke />
|
| 1694 |
+
<ellipse x="48.41" y="68.5" w="13.0" h="13.0" />
|
| 1695 |
+
<fillstroke />
|
| 1696 |
+
<stroke />
|
| 1697 |
+
<rect x="53.47" y="43.5" w="2.88" h="6" />
|
| 1698 |
+
<fillstroke />
|
| 1699 |
+
<stroke />
|
| 1700 |
+
<ellipse x="48.41" y="49.5" w="13.0" h="13.0" />
|
| 1701 |
+
<fillstroke />
|
| 1702 |
+
<stroke />
|
| 1703 |
+
<ellipse x="48.41" y="30.5" w="13.0" h="13.0" />
|
| 1704 |
+
<fillstroke />
|
| 1705 |
+
<stroke />
|
| 1706 |
+
<rect x="91.66" y="48.5" w="11.5" h="14" />
|
| 1707 |
+
<fillstroke />
|
| 1708 |
+
<stroke />
|
| 1709 |
+
</foreground>
|
| 1710 |
+
</shape><shape h="120.0" w="117.0" aspect="variable" strokewidth="inherit" name="PressRemovalCastIronThimble" displayName="PressRemovalCastIronThimble">
|
| 1711 |
+
<foreground>
|
| 1712 |
+
<rect x="0" y="-0.25" w="116.32" h="120" />
|
| 1713 |
+
<fillstroke />
|
| 1714 |
+
<stroke />
|
| 1715 |
+
<rect x="18.84" y="17" w="25" h="85.5" />
|
| 1716 |
+
<fillstroke />
|
| 1717 |
+
<stroke />
|
| 1718 |
+
<rect x="43.84" y="17" w="60" h="16" />
|
| 1719 |
+
<fillstroke />
|
| 1720 |
+
<stroke />
|
| 1721 |
+
<rect x="43.84" y="86.5" w="60" h="16" />
|
| 1722 |
+
<fillstroke />
|
| 1723 |
+
<stroke />
|
| 1724 |
+
<path>
|
| 1725 |
+
<move x="20.84" y="89.0" />
|
| 1726 |
+
<line x="41.84" y="89.0" />
|
| 1727 |
+
<line x="41.84" y="82.0" />
|
| 1728 |
+
<line x="28.84" y="73.0" />
|
| 1729 |
+
<line x="41.84" y="65.0" />
|
| 1730 |
+
<line x="41.84" y="55.0" />
|
| 1731 |
+
<line x="27.84" y="46.0" />
|
| 1732 |
+
<line x="41.84" y="39.0" />
|
| 1733 |
+
<line x="41.84" y="30.0" />
|
| 1734 |
+
<line x="18.84" y="30.0" />
|
| 1735 |
+
<line x="18.84" y="89.0" />
|
| 1736 |
+
<line x="20.84" y="89.0" />
|
| 1737 |
+
</path>
|
| 1738 |
+
<fillstroke />
|
| 1739 |
+
<stroke />
|
| 1740 |
+
</foreground>
|
| 1741 |
+
</shape><shape h="33.0" w="36.0" aspect="variable" strokewidth="inherit" name="pump" displayName="pump"><foreground><rect x="16.7" y="-0.42" w="19.3" h="9.86" /><fillstroke /><stroke /><ellipse x="-0.004999999999999005" y="-0.4250000000000007" w="32.85" h="32.85" /><fillstroke /><stroke /></foreground></shape><shape h="33.0" w="37.0" aspect="variable" strokewidth="inherit" name="pump_left" displayName="pump_left">
|
| 1742 |
+
<foreground>
|
| 1743 |
+
<path>
|
| 1744 |
+
<move x="5.0" y="10" />
|
| 1745 |
+
<line x="0.0" y="10" />
|
| 1746 |
+
<line x="0.0" y="0" />
|
| 1747 |
+
<line x="20.0" y="0" />
|
| 1748 |
+
</path>
|
| 1749 |
+
<fillstroke />
|
| 1750 |
+
<stroke />
|
| 1751 |
+
<ellipse x="3.5" y="0" w="33.0" h="33.0" />
|
| 1752 |
+
<fillstroke />
|
| 1753 |
+
<stroke />
|
| 1754 |
+
</foreground>
|
| 1755 |
+
</shape><shape h="66.0" w="120.0" aspect="variable" strokewidth="inherit" name="refrigerator" displayName="refrigerator">
|
| 1756 |
+
<foreground>
|
| 1757 |
+
|
| 1758 |
+
|
| 1759 |
+
<rect x="0" y="6" w="120" h="60" />
|
| 1760 |
+
<fillstroke />
|
| 1761 |
+
<stroke />
|
| 1762 |
+
|
| 1763 |
+
|
| 1764 |
+
<path>
|
| 1765 |
+
<move x="0" y="6" />
|
| 1766 |
+
<line x="2" y="0" />
|
| 1767 |
+
<line x="118" y="0" />
|
| 1768 |
+
<line x="120" y="6" />
|
| 1769 |
+
<close />
|
| 1770 |
+
</path>
|
| 1771 |
+
<fillstroke />
|
| 1772 |
+
<stroke />
|
| 1773 |
+
</foreground>
|
| 1774 |
+
</shape><shape h="60.0" w="109.0" aspect="variable" strokewidth="inherit" name="roller_crusher" displayName="roller_crusher"><foreground><rect x="-0.07" y="0" w="109" h="60" /><fillstroke /><stroke /><ellipse x="7.93" y="3.5" w="53.0" h="53.0" /><fillstroke /><stroke /><ellipse x="48.93000000000001" y="3.5" w="53.0" h="53.0" /><fillstroke /><stroke /><ellipse x="8.0" y="3.5" w="53.0" h="53.0" /><stroke /></foreground></shape><shape h="55.0" w="174.0" aspect="variable" strokewidth="inherit" name="rotary_kiln" displayName="rotary_kiln"><foreground><roundrect arcsize="5.85" x="0" y="4.64" w="174" h="39" /><fillstroke /><stroke /><rect x="10" y="1" w="15" h="54" /><fillstroke /><stroke /><rect x="68" y="2" w="5" h="45" /><fillstroke /><stroke /><rect x="68" y="7" w="5" h="4" /><fillstroke /><stroke /><rect x="68" y="16" w="5" h="4" /><fillstroke /><stroke /><rect x="68" y="25" w="5" h="4" /><fillstroke /><stroke /><rect x="68" y="34" w="5" h="4" /><fillstroke /><stroke /><rect x="68" y="43" w="5" h="4" /><fillstroke /><stroke /><rect x="149" y="0" w="15" h="54" /><fillstroke /><stroke /></foreground></shape><shape h="200.0" w="61.0" aspect="variable" strokewidth="inherit" name="scrubber" displayName="scrubber">
|
| 1775 |
+
<foreground>
|
| 1776 |
+
|
| 1777 |
+
|
| 1778 |
+
<path>
|
| 1779 |
+
<move x="21.99" y="0" />
|
| 1780 |
+
<line x="39.01" y="0" />
|
| 1781 |
+
<line x="39.01" y="39" />
|
| 1782 |
+
<line x="61" y="61.97" />
|
| 1783 |
+
<line x="61" y="200" />
|
| 1784 |
+
<line x="0" y="200" />
|
| 1785 |
+
<line x="0" y="61.97" />
|
| 1786 |
+
<line x="21.99" y="39" />
|
| 1787 |
+
<close />
|
| 1788 |
+
</path>
|
| 1789 |
+
<fillstroke />
|
| 1790 |
+
<stroke />
|
| 1791 |
+
</foreground>
|
| 1792 |
+
</shape><shape h="118.0" w="32.0" aspect="variable" strokewidth="inherit" name="self-evaporator" displayName="self-evaporator"><foreground><ellipse x="0.0" y="0.0" w="32.0" h="24.16" /><fillstroke /><stroke /><ellipse x="0.0" y="92.0" w="32.0" h="26.0" /><fillstroke /><stroke /><rect x="0" y="15.86" w="32" h="88.28" /><fillstroke /><stroke /><rect x="0" y="12.21" w="32" h="3.65" /><fillstroke /><stroke /></foreground></shape><shape h="29.0" w="79.0" aspect="variable" strokewidth="inherit" name="separator" displayName="separator">
|
| 1793 |
+
<foreground>
|
| 1794 |
+
|
| 1795 |
+
|
| 1796 |
+
<rect x="60.83" y="15.54" w="18.17" h="13.46" />
|
| 1797 |
+
<fillstroke />
|
| 1798 |
+
<stroke />
|
| 1799 |
+
|
| 1800 |
+
|
| 1801 |
+
<path>
|
| 1802 |
+
<move x="0.0" y="0.0" />
|
| 1803 |
+
<line x="70.31" y="14.5" />
|
| 1804 |
+
<line x="0.0" y="29.0" />
|
| 1805 |
+
<close />
|
| 1806 |
+
</path>
|
| 1807 |
+
<fillstroke />
|
| 1808 |
+
<stroke />
|
| 1809 |
+
|
| 1810 |
+
|
| 1811 |
+
<rect x="0" y="0" w="79" h="16.57" />
|
| 1812 |
+
<fillstroke />
|
| 1813 |
+
<stroke />
|
| 1814 |
+
</foreground>
|
| 1815 |
+
</shape><shape h="70.0" w="234.0" aspect="variable" strokewidth="inherit" name="Shnek" displayName="Shnek">
|
| 1816 |
+
<foreground>
|
| 1817 |
+
<rect x="0" y="0" w="17" h="70" />
|
| 1818 |
+
<fillstroke />
|
| 1819 |
+
<stroke />
|
| 1820 |
+
<rect x="17" y="9.5" w="165" h="51" />
|
| 1821 |
+
<fillstroke />
|
| 1822 |
+
<stroke />
|
| 1823 |
+
<rect x="182" y="0" w="17" h="70" />
|
| 1824 |
+
<fillstroke />
|
| 1825 |
+
<stroke />
|
| 1826 |
+
<rect x="199" y="25" w="35" h="20" />
|
| 1827 |
+
<fillstroke />
|
| 1828 |
+
<stroke />
|
| 1829 |
+
<rect x="17" y="19.3" w="163" h="5.2" />
|
| 1830 |
+
<fillstroke />
|
| 1831 |
+
<stroke />
|
| 1832 |
+
<path>
|
| 1833 |
+
<move x="22.7" y="24.44" />
|
| 1834 |
+
<curve x1="24.93" y1="28.47" x2="27.15" y2="32.5" x3="31.62" y3="23.56" />
|
| 1835 |
+
<curve x1="34.39" y1="18.03" x2="37.15" y2="12.5" x3="39.43" y3="15.77" />
|
| 1836 |
+
<curve x1="41.72" y1="19.05" x2="41.72" x3="41.72" y2="19.05" y3="19.05" />
|
| 1837 |
+
</path>
|
| 1838 |
+
<stroke />
|
| 1839 |
+
<path>
|
| 1840 |
+
<move x="45.0" y="24.44" />
|
| 1841 |
+
<curve x1="47.22" y1="28.47" x2="49.44" y2="32.5" x3="53.91" y3="23.56" />
|
| 1842 |
+
<curve x1="56.68" y1="18.03" x2="59.44" y2="12.5" x3="61.72" y3="15.77" />
|
| 1843 |
+
<curve x1="64.01" y1="19.05" x2="64.01" x3="64.01" y2="19.05" y3="19.05" />
|
| 1844 |
+
</path>
|
| 1845 |
+
<stroke />
|
| 1846 |
+
<path>
|
| 1847 |
+
<move x="67.0" y="24.44" />
|
| 1848 |
+
<curve x1="69.22" y1="28.47" x2="71.44" y2="32.5" x3="75.91" y3="23.56" />
|
| 1849 |
+
<curve x1="78.68" y1="18.03" x2="81.44" y2="12.5" x3="83.72" y3="15.77" />
|
| 1850 |
+
<curve x1="86.01" y1="19.05" x2="86.01" x3="86.01" y2="19.05" y3="19.05" />
|
| 1851 |
+
</path>
|
| 1852 |
+
<stroke />
|
| 1853 |
+
<path>
|
| 1854 |
+
<move x="89.0" y="24.44" />
|
| 1855 |
+
<curve x1="91.22" y1="28.47" x2="93.44" y2="32.5" x3="97.91" y3="23.56" />
|
| 1856 |
+
<curve x1="100.68" y1="18.03" x2="103.44" y2="12.5" x3="105.72" y3="15.77" />
|
| 1857 |
+
<curve x1="108.01" y1="19.05" x2="108.01" x3="108.01" y2="19.05" y3="19.05" />
|
| 1858 |
+
</path>
|
| 1859 |
+
<stroke />
|
| 1860 |
+
<path>
|
| 1861 |
+
<move x="112.0" y="24.44" />
|
| 1862 |
+
<curve x1="114.23" y1="28.47" x2="116.45" y2="32.5" x3="120.92" y3="23.56" />
|
| 1863 |
+
<curve x1="123.69" y1="18.03" x2="126.45" y2="12.5" x3="128.73" y3="15.77" />
|
| 1864 |
+
<curve x1="131.02" y1="19.05" x2="131.02" x3="131.02" y2="19.05" y3="19.05" />
|
| 1865 |
+
</path>
|
| 1866 |
+
<stroke />
|
| 1867 |
+
<path>
|
| 1868 |
+
<move x="134.0" y="24.44" />
|
| 1869 |
+
<curve x1="136.22" y1="28.47" x2="138.44" y2="32.5" x3="142.91" y3="23.56" />
|
| 1870 |
+
<curve x1="145.68" y1="18.03" x2="148.44" y2="12.5" x3="150.72" y3="15.77" />
|
| 1871 |
+
<curve x1="153.01" y1="19.05" x2="153.01" x3="153.01" y2="19.05" y3="19.05" />
|
| 1872 |
+
</path>
|
| 1873 |
+
<stroke />
|
| 1874 |
+
<path>
|
| 1875 |
+
<move x="156.0" y="24.44" />
|
| 1876 |
+
<curve x1="158.23" y1="28.47" x2="160.45" y2="32.5" x3="164.92" y3="23.56" />
|
| 1877 |
+
<curve x1="167.69" y1="18.03" x2="170.45" y2="12.5" x3="172.73" y3="15.77" />
|
| 1878 |
+
<curve x1="175.02" y1="19.05" x2="175.02" x3="175.02" y2="19.05" y3="19.05" />
|
| 1879 |
+
</path>
|
| 1880 |
+
<stroke />
|
| 1881 |
+
<rect x="17" y="44.3" w="163" h="5.2" />
|
| 1882 |
+
<fillstroke />
|
| 1883 |
+
<stroke />
|
| 1884 |
+
<path>
|
| 1885 |
+
<move x="22.7" y="49.44" />
|
| 1886 |
+
<curve x1="24.93" y1="53.47" x2="27.15" y2="57.5" x3="31.62" y3="48.56" />
|
| 1887 |
+
<curve x1="34.39" y1="43.03" x2="37.15" y2="37.5" x3="39.43" y3="40.77" />
|
| 1888 |
+
<curve x1="41.72" y1="44.05" x2="41.72" x3="41.72" y2="44.05" y3="44.05" />
|
| 1889 |
+
</path>
|
| 1890 |
+
<stroke />
|
| 1891 |
+
<path>
|
| 1892 |
+
<move x="45.0" y="49.44" />
|
| 1893 |
+
<curve x1="47.22" y1="53.47" x2="49.44" y2="57.5" x3="53.91" y3="48.56" />
|
| 1894 |
+
<curve x1="56.68" y1="43.03" x2="59.44" y2="37.5" x3="61.72" y3="40.77" />
|
| 1895 |
+
<curve x1="64.01" y1="44.05" x2="64.01" x3="64.01" y2="44.05" y3="44.05" />
|
| 1896 |
+
</path>
|
| 1897 |
+
<stroke />
|
| 1898 |
+
<path>
|
| 1899 |
+
<move x="67.0" y="49.44" />
|
| 1900 |
+
<curve x1="69.22" y1="53.47" x2="71.44" y2="57.5" x3="75.91" y3="48.56" />
|
| 1901 |
+
<curve x1="78.68" y1="43.03" x2="81.44" y2="37.5" x3="83.72" y3="40.77" />
|
| 1902 |
+
<curve x1="86.01" y1="44.05" x2="86.01" x3="86.01" y2="44.05" y3="44.05" />
|
| 1903 |
+
</path>
|
| 1904 |
+
<stroke />
|
| 1905 |
+
<path>
|
| 1906 |
+
<move x="88.99" y="49.44" />
|
| 1907 |
+
<curve x1="91.22" y1="53.47" x2="93.44" y2="57.5" x3="97.91" y3="48.56" />
|
| 1908 |
+
<curve x1="100.68" y1="43.03" x2="103.44" y2="37.5" x3="105.72" y3="40.77" />
|
| 1909 |
+
<curve x1="108.01" y1="44.05" x2="108.01" x3="108.01" y2="44.05" y3="44.05" />
|
| 1910 |
+
</path>
|
| 1911 |
+
<stroke />
|
| 1912 |
+
<path>
|
| 1913 |
+
<move x="112.01" y="49.44" />
|
| 1914 |
+
<curve x1="114.23" y1="53.47" x2="116.45" y2="57.5" x3="120.92" y3="48.56" />
|
| 1915 |
+
<curve x1="123.69" y1="43.03" x2="126.45" y2="37.5" x3="128.73" y3="40.77" />
|
| 1916 |
+
<curve x1="131.02" y1="44.05" x2="131.02" x3="131.02" y2="44.05" y3="44.05" />
|
| 1917 |
+
</path>
|
| 1918 |
+
<stroke />
|
| 1919 |
+
<path>
|
| 1920 |
+
<move x="133.99" y="49.44" />
|
| 1921 |
+
<curve x1="136.22" y1="53.47" x2="138.44" y2="57.5" x3="142.91" y3="48.56" />
|
| 1922 |
+
<curve x1="145.68" y1="43.03" x2="148.44" y2="37.5" x3="150.72" y3="40.77" />
|
| 1923 |
+
<curve x1="153.01" y1="44.05" x2="153.01" x3="153.01" y2="44.05" y3="44.05" />
|
| 1924 |
+
</path>
|
| 1925 |
+
<stroke />
|
| 1926 |
+
<path>
|
| 1927 |
+
<move x="156.01" y="49.44" />
|
| 1928 |
+
<curve x1="158.23" y1="53.47" x2="160.45" y2="57.5" x3="164.92" y3="48.56" />
|
| 1929 |
+
<curve x1="167.69" y1="43.03" x2="170.45" y2="37.5" x3="172.73" y3="40.77" />
|
| 1930 |
+
<curve x1="175.02" y1="44.05" x2="175.02" x3="175.02" y2="44.05" y3="44.05" />
|
| 1931 |
+
</path>
|
| 1932 |
+
<stroke />
|
| 1933 |
+
</foreground>
|
| 1934 |
+
</shape><shape h="106.0" w="81.0" aspect="variable" strokewidth="inherit" name="silo" displayName="silo"><foreground><path><move x="0.0" y="0.0" /><line x="80.0" y="0.0" /><line x="80.0" y="87.0" /><line x="40.0" y="106.0" /><line x="0.0" y="87.0" /><close /></path><fillstroke /><stroke /><path><move x="0.0" y="87.0" /><line x="80.0" y="87.0" /></path><fillstroke /><stroke /></foreground></shape><shape h="28.0" w="186.0" aspect="variable" strokewidth="inherit" name="steam_line_section" displayName="steam_line_section"><foreground><rect x="0" y="7.23" w="185" h="13.77" /><fillstroke /><stroke /><rect x="6" y="0" w="8" h="28" /><fillstroke /><stroke /><rect x="169" y="0" w="8" h="28" /><fillstroke /><stroke /></foreground></shape><shape h="163.0" w="107.0" aspect="variable" strokewidth="inherit" name="stop_valve" displayName="stop_valve">
|
| 1935 |
+
<foreground>
|
| 1936 |
+
<rect x="38" y="51" w="31" h="19" />
|
| 1937 |
+
<fillstroke />
|
| 1938 |
+
<stroke />
|
| 1939 |
+
<rect x="38" y="51" w="31" h="19" />
|
| 1940 |
+
<fillstroke />
|
| 1941 |
+
<stroke />
|
| 1942 |
+
<rect x="44" y="0" w="19" h="144" />
|
| 1943 |
+
<fillstroke />
|
| 1944 |
+
<stroke />
|
| 1945 |
+
<path>
|
| 1946 |
+
<move x="0" y="144" />
|
| 1947 |
+
<line x="107" y="144" />
|
| 1948 |
+
<line x="107" y="163" />
|
| 1949 |
+
<line x="94" y="163" />
|
| 1950 |
+
<line x="94" y="157" />
|
| 1951 |
+
<line x="76" y="157" />
|
| 1952 |
+
<line x="76" y="163" />
|
| 1953 |
+
<line x="63" y="163" />
|
| 1954 |
+
<line x="63" y="157" />
|
| 1955 |
+
<line x="44" y="157" />
|
| 1956 |
+
<line x="44" y="163" />
|
| 1957 |
+
<line x="31" y="163" />
|
| 1958 |
+
<line x="31" y="157" />
|
| 1959 |
+
<line x="13" y="157" />
|
| 1960 |
+
<line x="13" y="163" />
|
| 1961 |
+
<line x="0" y="163" />
|
| 1962 |
+
<close />
|
| 1963 |
+
</path>
|
| 1964 |
+
<fillstroke />
|
| 1965 |
+
<stroke />
|
| 1966 |
+
</foreground>
|
| 1967 |
+
</shape><shape h="160.0" w="62.0" aspect="variable" strokewidth="inherit" name="supercharger" displayName="supercharger"><foreground><path><move x="0.07" y="112.16" /><line x="59.94" y="112.02" /></path><fillstroke /><stroke /><roundrect arcsize="7.17" x="0.24" y="89.76" w="59.76" h="70.24" /><fillstroke /><stroke /><rect x="10.53" y="26.93" w="39.18" h="47.61" /><fillstroke /><stroke /><roundrect arcsize="2.15" x="5.03" y="0" w="50.2" h="26.93" /><fillstroke /><stroke /><rect x="5.52" y="37.46" w="49.22" h="4.68" /><fillstroke /><stroke /><path><move x="53.39" y="116.28999999999999" /><line x="53.39" y="154.53" /></path><fillstroke /><stroke /><path><move x="48.98" y="116.28999999999999" /><line x="48.98" y="154.53" /></path><fillstroke /><stroke /><path><move x="44.57" y="116.28999999999999" /><line x="44.57" y="154.53" /></path><fillstroke /><stroke /><path><move x="40.16" y="116.28999999999999" /><line x="40.16" y="154.54" /></path><fillstroke /><stroke /><path><move x="35.76" y="116.28" /><line x="35.76" y="154.53" /></path><fillstroke /><stroke /><path><move x="31.35" y="116.28" /><line x="31.35" y="154.53" /></path><fillstroke /><stroke /><path><move x="26.94" y="116.28999999999999" /><line x="26.94" y="154.53" /></path><fillstroke /><stroke /><path><move x="22.53" y="116.28999999999999" /><line x="22.53" y="154.53" /></path><fillstroke /><stroke /><path><move x="18.12" y="116.28999999999999" /><line x="18.12" y="154.53" /></path><fillstroke /><stroke /><path><move x="13.709999999999999" y="116.28999999999999" /><line x="13.710000000000003" y="154.54" /></path><fillstroke /><stroke /><path><move x="9.309999999999999" y="116.28" /><line x="9.310000000000002" y="154.53" /></path><fillstroke /><stroke /><path><move x="4.8999999999999995" y="116.28999999999999" /><line x="4.900000000000001" y="154.53" /></path><fillstroke /><stroke /><path><move x="0.07" y="112.16" /><line x="59.94" y="112.02" /></path><fillstroke /><stroke /><rect x="27.18" y="74.54" w="5.88" h="37.46" /><fillstroke /><stroke /></foreground></shape><shape h="61.0" w="120.0" aspect="variable" strokewidth="inherit" name="tank" displayName="tank"><foreground><roundrect arcsize="9" x="0" y="0" w="120" h="60" /><fillstroke /><stroke /></foreground></shape><shape h="22.0" w="80.0" aspect="variable" strokewidth="inherit" name="thickener" displayName="thickener"><foreground><path><move x="0.0" y="0.0" /><line x="80.0" y="0.0" /><line x="80.0" y="4.58" /><line x="40.0" y="22.0" /><line x="0.0" y="4.58" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="123.0" w="111.0" aspect="variable" strokewidth="inherit" name="transformers_auxiliary" displayName="transformers_auxiliary">
|
| 1968 |
+
<foreground>
|
| 1969 |
+
<ellipse x="85.69999999999999" y="97.19999999999999" w="24.8" h="24.8" />
|
| 1970 |
+
<fillstroke />
|
| 1971 |
+
<stroke />
|
| 1972 |
+
<path>
|
| 1973 |
+
<move x="93.3" y="114.39999999999999" />
|
| 1974 |
+
<line x="98.1" y="104.79999999999998" />
|
| 1975 |
+
<line x="102.9" y="114.39999999999999" />
|
| 1976 |
+
<close />
|
| 1977 |
+
</path>
|
| 1978 |
+
<fillstroke />
|
| 1979 |
+
<stroke />
|
| 1980 |
+
<ellipse x="64.69999999999999" y="97.19999999999999" w="24.8" h="24.8" />
|
| 1981 |
+
<fillstroke />
|
| 1982 |
+
<stroke />
|
| 1983 |
+
<path>
|
| 1984 |
+
<move x="72.3" y="114.39999999999999" />
|
| 1985 |
+
<line x="77.1" y="104.79999999999998" />
|
| 1986 |
+
<line x="81.9" y="114.39999999999999" />
|
| 1987 |
+
<close />
|
| 1988 |
+
</path>
|
| 1989 |
+
<fillstroke />
|
| 1990 |
+
<stroke />
|
| 1991 |
+
<ellipse x="74.69999999999999" y="79.0" w="24.8" h="24.8" />
|
| 1992 |
+
<fillstroke />
|
| 1993 |
+
<stroke />
|
| 1994 |
+
<path>
|
| 1995 |
+
<move x="82.3" y="95.6" />
|
| 1996 |
+
<line x="87.1" y="85.99999999999999" />
|
| 1997 |
+
<line x="91.89999999999999" y="95.6" />
|
| 1998 |
+
<close />
|
| 1999 |
+
</path>
|
| 2000 |
+
<fillstroke />
|
| 2001 |
+
<stroke />
|
| 2002 |
+
<ellipse x="64.69999999999999" y="97.19999999999999" w="24.8" h="24.8" />
|
| 2003 |
+
|
| 2004 |
+
<stroke />
|
| 2005 |
+
<path>
|
| 2006 |
+
<move x="87.1" y="79.0" />
|
| 2007 |
+
<line x="87.11" y="2.0" />
|
| 2008 |
+
<line x="87.06" y="0.53" />
|
| 2009 |
+
</path>
|
| 2010 |
+
<fillstroke />
|
| 2011 |
+
<stroke />
|
| 2012 |
+
<path>
|
| 2013 |
+
<move x="87.5" y="21.0" />
|
| 2014 |
+
<line x="105.56" y="21.0" />
|
| 2015 |
+
<line x="105.56" y="0.0" />
|
| 2016 |
+
</path>
|
| 2017 |
+
|
| 2018 |
+
<stroke />
|
| 2019 |
+
<path>
|
| 2020 |
+
<move x="12.1" y="79.0" />
|
| 2021 |
+
<line x="12.11" y="24.0" />
|
| 2022 |
+
<line x="12.06" y="0.53" />
|
| 2023 |
+
</path>
|
| 2024 |
+
|
| 2025 |
+
<stroke />
|
| 2026 |
+
<path>
|
| 2027 |
+
<move x="23.099999999999998" y="54.0" />
|
| 2028 |
+
<line x="1.099999999999996" y="54.0" />
|
| 2029 |
+
<line x="1.0999999999999996" y="35.0" />
|
| 2030 |
+
<line x="23.1" y="35.0" />
|
| 2031 |
+
<close />
|
| 2032 |
+
</path>
|
| 2033 |
+
<fillstroke />
|
| 2034 |
+
<stroke />
|
| 2035 |
+
<path>
|
| 2036 |
+
<move x="12.46" y="21.0" />
|
| 2037 |
+
<line x="30.44" y="21.0" />
|
| 2038 |
+
<line x="30.44" y="0.0" />
|
| 2039 |
+
</path>
|
| 2040 |
+
|
| 2041 |
+
<stroke />
|
| 2042 |
+
<path>
|
| 2043 |
+
<move x="98.1" y="54.0" />
|
| 2044 |
+
<line x="76.1" y="54.0" />
|
| 2045 |
+
<line x="76.1" y="35.0" />
|
| 2046 |
+
<line x="98.1" y="35.0" />
|
| 2047 |
+
<close />
|
| 2048 |
+
</path>
|
| 2049 |
+
<fillstroke />
|
| 2050 |
+
<stroke />
|
| 2051 |
+
<ellipse x="-0.4299999999999997" y="96.89999999999999" w="24.8" h="24.8" />
|
| 2052 |
+
<fillstroke />
|
| 2053 |
+
<stroke />
|
| 2054 |
+
<ellipse x="-0.3000000000000007" y="79.19999999999999" w="24.8" h="24.8" />
|
| 2055 |
+
<fillstroke />
|
| 2056 |
+
<stroke />
|
| 2057 |
+
<ellipse x="-0.4299999999999997" y="96.89999999999999" w="24.8" h="24.8" />
|
| 2058 |
+
|
| 2059 |
+
<stroke />
|
| 2060 |
+
<ellipse x="85.69999999999999" y="97.19999999999999" w="24.8" h="24.8" />
|
| 2061 |
+
|
| 2062 |
+
<stroke />
|
| 2063 |
+
</foreground>
|
| 2064 |
+
</shape><shape h="134.0" w="126.0" aspect="variable" strokewidth="inherit" name="transformer_communication" displayName="transformer_communication">
|
| 2065 |
+
<foreground>
|
| 2066 |
+
<rect x="12.4" y="78" w="22" h="19" />
|
| 2067 |
+
<fillstroke />
|
| 2068 |
+
<stroke />
|
| 2069 |
+
<ellipse x="0.0" y="9.999999999999998" w="24.8" h="24.8" />
|
| 2070 |
+
<fillstroke />
|
| 2071 |
+
<stroke />
|
| 2072 |
+
<path>
|
| 2073 |
+
<move x="7.600000000000004" y="27.2" />
|
| 2074 |
+
<line x="12.4" y="17.6" />
|
| 2075 |
+
<line x="17.200000000000003" y="27.2" />
|
| 2076 |
+
<close />
|
| 2077 |
+
</path>
|
| 2078 |
+
<fillstroke />
|
| 2079 |
+
<stroke />
|
| 2080 |
+
<ellipse x="21.0" y="9.999999999999998" w="24.8" h="24.8" />
|
| 2081 |
+
<fillstroke />
|
| 2082 |
+
<stroke />
|
| 2083 |
+
<path>
|
| 2084 |
+
<move x="28.6" y="27.199999999999996" />
|
| 2085 |
+
<line x="33.4" y="17.599999999999994" />
|
| 2086 |
+
<line x="38.2" y="27.199999999999996" />
|
| 2087 |
+
<close />
|
| 2088 |
+
</path>
|
| 2089 |
+
<fillstroke />
|
| 2090 |
+
<stroke />
|
| 2091 |
+
<ellipse x="10.999999999999998" y="28.200000000000003" w="24.8" h="24.8" />
|
| 2092 |
+
<fillstroke />
|
| 2093 |
+
<stroke />
|
| 2094 |
+
<path>
|
| 2095 |
+
<move x="23.005898384862245" y="40.1" />
|
| 2096 |
+
<line x="29.934101615137752" y="44.1" />
|
| 2097 |
+
</path>
|
| 2098 |
+
<fillstroke />
|
| 2099 |
+
<stroke />
|
| 2100 |
+
<path>
|
| 2101 |
+
<move x="23.2" y="32.2" />
|
| 2102 |
+
<line x="23.2" y="40.2" />
|
| 2103 |
+
</path>
|
| 2104 |
+
<fillstroke />
|
| 2105 |
+
<stroke />
|
| 2106 |
+
<path>
|
| 2107 |
+
<move x="23.664101615137753" y="40.1" />
|
| 2108 |
+
<line x="16.735898384862246" y="44.1" />
|
| 2109 |
+
</path>
|
| 2110 |
+
<fillstroke />
|
| 2111 |
+
<stroke />
|
| 2112 |
+
<ellipse x="0.0" y="9.999999999999998" w="24.8" h="24.8" />
|
| 2113 |
+
|
| 2114 |
+
<stroke />
|
| 2115 |
+
<path>
|
| 2116 |
+
<move x="23.4" y="53.0" />
|
| 2117 |
+
<line x="23.44" y="130.0" />
|
| 2118 |
+
<line x="23.45" y="131.47" />
|
| 2119 |
+
</path>
|
| 2120 |
+
|
| 2121 |
+
<stroke />
|
| 2122 |
+
<path>
|
| 2123 |
+
<move x="23.0" y="111.0" />
|
| 2124 |
+
<line x="5.0" y="111.0" />
|
| 2125 |
+
<line x="5.0" y="132.0" />
|
| 2126 |
+
</path>
|
| 2127 |
+
|
| 2128 |
+
<stroke />
|
| 2129 |
+
<ellipse x="96.0" y="10.999999999999998" w="24.8" h="24.8" />
|
| 2130 |
+
<fillstroke />
|
| 2131 |
+
<stroke />
|
| 2132 |
+
<path>
|
| 2133 |
+
<move x="103.60000000000001" y="28.20000000000001" />
|
| 2134 |
+
<line x="108.4" y="18.6" />
|
| 2135 |
+
<line x="113.2" y="28.20000000000001" />
|
| 2136 |
+
<close />
|
| 2137 |
+
</path>
|
| 2138 |
+
<fillstroke />
|
| 2139 |
+
<stroke />
|
| 2140 |
+
<ellipse x="75.0" y="10.999999999999998" w="24.8" h="24.8" />
|
| 2141 |
+
<fillstroke />
|
| 2142 |
+
<stroke />
|
| 2143 |
+
<path>
|
| 2144 |
+
<move x="87.00589838486225" y="22.9" />
|
| 2145 |
+
<line x="93.93410161513775" y="26.9" />
|
| 2146 |
+
</path>
|
| 2147 |
+
<fillstroke />
|
| 2148 |
+
<stroke />
|
| 2149 |
+
<path>
|
| 2150 |
+
<move x="87.2" y="15.0" />
|
| 2151 |
+
<line x="87.2" y="23.0" />
|
| 2152 |
+
</path>
|
| 2153 |
+
<fillstroke />
|
| 2154 |
+
<stroke />
|
| 2155 |
+
<path>
|
| 2156 |
+
<move x="87.66410161513775" y="22.9" />
|
| 2157 |
+
<line x="80.73589838486225" y="26.9" />
|
| 2158 |
+
</path>
|
| 2159 |
+
<fillstroke />
|
| 2160 |
+
<stroke />
|
| 2161 |
+
<ellipse x="86.0" y="28.0" w="24.8" h="24.8" />
|
| 2162 |
+
<fillstroke />
|
| 2163 |
+
<stroke />
|
| 2164 |
+
<path>
|
| 2165 |
+
<move x="98.00589838486225" y="39.9" />
|
| 2166 |
+
<line x="104.93410161513775" y="43.9" />
|
| 2167 |
+
</path>
|
| 2168 |
+
<fillstroke />
|
| 2169 |
+
<stroke />
|
| 2170 |
+
<path>
|
| 2171 |
+
<move x="98.2" y="32.0" />
|
| 2172 |
+
<line x="98.2" y="40.0" />
|
| 2173 |
+
</path>
|
| 2174 |
+
<fillstroke />
|
| 2175 |
+
<stroke />
|
| 2176 |
+
<path>
|
| 2177 |
+
<move x="98.66410161513775" y="39.9" />
|
| 2178 |
+
<line x="91.73589838486225" y="43.9" />
|
| 2179 |
+
</path>
|
| 2180 |
+
|
| 2181 |
+
<stroke />
|
| 2182 |
+
<ellipse x="75.0" y="10.999999999999998" w="24.8" h="24.8" />
|
| 2183 |
+
|
| 2184 |
+
<stroke />
|
| 2185 |
+
<path>
|
| 2186 |
+
<move x="98.4" y="53.0" />
|
| 2187 |
+
<line x="98.44" y="130.0" />
|
| 2188 |
+
<line x="98.44" y="131.47" />
|
| 2189 |
+
</path>
|
| 2190 |
+
|
| 2191 |
+
<stroke />
|
| 2192 |
+
<rect x="87.4" y="78" w="22" h="19" />
|
| 2193 |
+
<fillstroke />
|
| 2194 |
+
<stroke />
|
| 2195 |
+
<path>
|
| 2196 |
+
<move x="98.04" y="111.0" />
|
| 2197 |
+
<line x="80.0" y="111.0" />
|
| 2198 |
+
<line x="80.0" y="132.0" />
|
| 2199 |
+
</path>
|
| 2200 |
+
|
| 2201 |
+
<stroke />
|
| 2202 |
+
<path>
|
| 2203 |
+
<move x="23.0" y="64.0" />
|
| 2204 |
+
<line x="46.0" y="64.0" />
|
| 2205 |
+
</path>
|
| 2206 |
+
<fillstroke />
|
| 2207 |
+
<stroke />
|
| 2208 |
+
<path>
|
| 2209 |
+
<move x="45.5" y="63.5" />
|
| 2210 |
+
<line x="45.5" y="53.5" />
|
| 2211 |
+
</path>
|
| 2212 |
+
<fillstroke />
|
| 2213 |
+
<stroke />
|
| 2214 |
+
<path>
|
| 2215 |
+
<move x="98.0" y="63.5" />
|
| 2216 |
+
<line x="121.0" y="63.5" />
|
| 2217 |
+
</path>
|
| 2218 |
+
<fillstroke />
|
| 2219 |
+
<stroke />
|
| 2220 |
+
<path>
|
| 2221 |
+
<move x="120.5" y="63.0" />
|
| 2222 |
+
<line x="120.5" y="53.0" />
|
| 2223 |
+
</path>
|
| 2224 |
+
<fillstroke />
|
| 2225 |
+
<stroke />
|
| 2226 |
+
<path>
|
| 2227 |
+
<move x="33.4" y="10.0" />
|
| 2228 |
+
<line x="33.4" y="0.0" />
|
| 2229 |
+
</path>
|
| 2230 |
+
<fillstroke />
|
| 2231 |
+
<stroke />
|
| 2232 |
+
<path>
|
| 2233 |
+
<move x="12.4" y="10.0" />
|
| 2234 |
+
<line x="12.4" y="1.7763568394002505e-15" />
|
| 2235 |
+
</path>
|
| 2236 |
+
<fillstroke />
|
| 2237 |
+
<stroke />
|
| 2238 |
+
<path>
|
| 2239 |
+
<move x="108.0" y="11.0" />
|
| 2240 |
+
<line x="108.0" y="1.0" />
|
| 2241 |
+
</path>
|
| 2242 |
+
<fillstroke />
|
| 2243 |
+
<stroke />
|
| 2244 |
+
<path>
|
| 2245 |
+
<move x="87.0" y="11.0" />
|
| 2246 |
+
<line x="87.0" y="1.0" />
|
| 2247 |
+
</path>
|
| 2248 |
+
<fillstroke />
|
| 2249 |
+
<stroke />
|
| 2250 |
+
<ellipse x="21.0" y="9.999999999999998" w="24.8" h="24.8" />
|
| 2251 |
+
|
| 2252 |
+
<stroke />
|
| 2253 |
+
<ellipse x="96.0" y="10.999999999999998" w="24.8" h="24.8" />
|
| 2254 |
+
|
| 2255 |
+
<stroke />
|
| 2256 |
+
</foreground>
|
| 2257 |
+
</shape><shape h="133.0" w="126.0" aspect="variable" strokewidth="inherit" name="transformer_voltage" displayName="transformer_voltage">
|
| 2258 |
+
<foreground>
|
| 2259 |
+
<ellipse x="16.0" y="0.0" w="40.0" h="36.0" />
|
| 2260 |
+
<fillstroke />
|
| 2261 |
+
<stroke />
|
| 2262 |
+
<ellipse x="0.0" y="26.0" w="40.0" h="36.0" />
|
| 2263 |
+
<fillstroke />
|
| 2264 |
+
<stroke />
|
| 2265 |
+
<ellipse x="32.0" y="26.0" w="40.0" h="36.0" />
|
| 2266 |
+
<fillstroke />
|
| 2267 |
+
<stroke />
|
| 2268 |
+
<rect x="103" y="17" w="22" h="35" />
|
| 2269 |
+
<fillstroke />
|
| 2270 |
+
<stroke />
|
| 2271 |
+
<path>
|
| 2272 |
+
<move x="36.0" y="59.0" />
|
| 2273 |
+
<line x="36.0" y="88.0" />
|
| 2274 |
+
</path>
|
| 2275 |
+
<fillstroke />
|
| 2276 |
+
<stroke />
|
| 2277 |
+
<path>
|
| 2278 |
+
<move x="35.95" y="85.33" />
|
| 2279 |
+
<line x="36.0" y="88.0" />
|
| 2280 |
+
<line x="114.0" y="88.0" />
|
| 2281 |
+
<line x="114.0" y="52.0" />
|
| 2282 |
+
</path>
|
| 2283 |
+
<stroke />
|
| 2284 |
+
<path>
|
| 2285 |
+
<move x="72.0" y="88.0" />
|
| 2286 |
+
<line x="72.0" y="132.0" />
|
| 2287 |
+
</path>
|
| 2288 |
+
<fillstroke />
|
| 2289 |
+
<stroke />
|
| 2290 |
+
<rect x="103" y="47" w="22" h="5" />
|
| 2291 |
+
<fillstroke />
|
| 2292 |
+
<stroke />
|
| 2293 |
+
<rect x="103" y="42" w="22" h="5" />
|
| 2294 |
+
<fillstroke />
|
| 2295 |
+
<stroke />
|
| 2296 |
+
<rect x="103" y="37" w="22" h="5" />
|
| 2297 |
+
<fillstroke />
|
| 2298 |
+
<stroke />
|
| 2299 |
+
<rect x="103" y="32" w="22" h="5" />
|
| 2300 |
+
<fillstroke />
|
| 2301 |
+
<stroke />
|
| 2302 |
+
<rect x="103" y="27" w="22" h="5" />
|
| 2303 |
+
<fillstroke />
|
| 2304 |
+
<stroke />
|
| 2305 |
+
<rect x="103" y="22" w="22" h="5" />
|
| 2306 |
+
<fillstroke />
|
| 2307 |
+
<stroke />
|
| 2308 |
+
<ellipse x="0.0" y="26.0" w="40.0" h="36.0" />
|
| 2309 |
+
|
| 2310 |
+
<stroke />
|
| 2311 |
+
<ellipse x="16.0" y="0.0" w="40.0" h="36.0" />
|
| 2312 |
+
|
| 2313 |
+
<stroke />
|
| 2314 |
+
</foreground>
|
| 2315 |
+
</shape><shape h="55.0" w="174.0" aspect="variable" strokewidth="inherit" name="tubular_apparatus" displayName="tubular_apparatus">
|
| 2316 |
+
<foreground>
|
| 2317 |
+
<path>
|
| 2318 |
+
<move x="11.54" y="13.14" />
|
| 2319 |
+
<line x="0.0" y="1.0" />
|
| 2320 |
+
<line x="23.0" y="1.0" />
|
| 2321 |
+
<line x="23.09" y="6.16" />
|
| 2322 |
+
</path>
|
| 2323 |
+
<fillstroke />
|
| 2324 |
+
<stroke />
|
| 2325 |
+
<roundrect arcsize="11.5" x="11.13" y="6" w="162" h="39" />
|
| 2326 |
+
<fillstroke />
|
| 2327 |
+
<stroke />
|
| 2328 |
+
<rect x="158.13" y="0.5" w="15" h="54" />
|
| 2329 |
+
<fillstroke />
|
| 2330 |
+
<stroke />
|
| 2331 |
+
<rect x="79.13" y="3" w="5" h="45" />
|
| 2332 |
+
<fillstroke />
|
| 2333 |
+
<stroke />
|
| 2334 |
+
<rect x="79.13" y="6" w="5" h="4" />
|
| 2335 |
+
<fillstroke />
|
| 2336 |
+
<stroke />
|
| 2337 |
+
<rect x="79.13" y="14" w="5" h="4" />
|
| 2338 |
+
<fillstroke />
|
| 2339 |
+
<stroke />
|
| 2340 |
+
<rect x="79.13" y="22" w="5" h="4" />
|
| 2341 |
+
<fillstroke />
|
| 2342 |
+
<stroke />
|
| 2343 |
+
<rect x="79.13" y="31" w="5" h="4" />
|
| 2344 |
+
<fillstroke />
|
| 2345 |
+
<stroke />
|
| 2346 |
+
<rect x="79.13" y="40" w="5" h="4" />
|
| 2347 |
+
<fillstroke />
|
| 2348 |
+
<stroke />
|
| 2349 |
+
</foreground>
|
| 2350 |
+
</shape><shape h="68.0" w="91.0" aspect="variable" strokewidth="inherit" name="turbogenerator" displayName="turbogenerator"><foreground><path><move x="0.0" y="34.78" /><line x="58.0" y="34.78" /></path><stroke /><path><move x="6.639999999999997" y="12.770000000000003" /><line x="17.06" y="18.14" /><line x="17.060000000000002" y="51.92" /><line x="6.640000000000001" y="57.29" /><close /></path><fillstroke /><stroke /><path><move x="45.92" y="67.51" /><line x="28.700000000000003" y="55.28" /><line x="28.700000000000003" y="12.719999999999999" /><line x="45.92" y="0.4900000000000091" /><close /></path><fillstroke /><stroke /><ellipse x="57.43801082543972" y="18.25801082543973" w="32.54397834912054" h="32.54397834912054" /><fillstroke /><stroke /><path><move x="62.06" y="34.79" /><curve x1="67.52" y1="21.93" x2="73.57" y2="33.84" x3="73.57" y3="33.84" /><curve x1="79.61" y1="45.75" x2="86.39" y2="34.79" x3="86.39" y3="34.79" /></path><stroke /></foreground></shape><shape h="129.0" w="53.0" aspect="variable" strokewidth="inherit" name="vacuum_crystallizer" displayName="vacuum_crystallizer"><foreground><path><move x="47.57" y="80.99000000000001" /><line x="47.57" y="92.58000000000001" /></path><fillstroke /><stroke /><path><move x="4.57" y="80.99000000000001" /><line x="4.57" y="92.58000000000001" /></path><fillstroke /><stroke /><rect x="8.63" y="0" w="34" h="34" /><fillstroke /><stroke /><rect x="4.67" y="80.68" w="42.66" h="11.89" /><fillstroke /><stroke /><rect x="13.46" y="34.27" w="24.88" h="39.31" /><fillstroke /><stroke /><path><move x="5.08" y="80.63" /><line x="13.08" y="73.57" /><line x="38.72" y="73.57" /><line x="46.72" y="80.63" /><close /></path><fillstroke /><stroke /><path><move x="46.72" y="92.72" /><line x="38.72" y="99.78" /><line x="13.079999999999998" y="99.78" /><line x="5.079999999999998" y="92.72" /><close /></path><fillstroke /><stroke /><rect x="13.46" y="99.78" w="24.88" h="24.19" /><fillstroke /><stroke /><path><move x="34.44999999999999" y="122.17999999999999" /><line x="25.89" y="128.01999999999998" /><line x="17.320000000000007" y="122.17999999999999" /><close /></path><fillstroke /><stroke /></foreground></shape><shape h="144.0" w="88.0" aspect="variable" strokewidth="inherit" name="vacuum_deaerator" displayName="vacuum_deaerator"><foreground><rect x="8.8" y="0" w="70.4" h="108.95" /><fillstroke /><stroke /><rect x="0" y="14.38" w="8.8" h="6.81" /><fillstroke /><stroke /><rect x="79.2" y="14.38" w="8.8" h="6.81" /><fillstroke /><stroke /><rect x="0" y="83.98" w="8.8" h="6.81" /><fillstroke /><stroke /><path><move x="79.2" y="108.95000000000002" /><line x="57.199999999999996" y="130.89000000000001" /><line x="30.799999999999997" y="130.89" /><line x="8.799999999999997" y="108.95000000000002" /><close /></path><fillstroke /><stroke /><rect x="30.31" y="130.89" w="27.38" h="12.11" /><fillstroke /><stroke /></foreground></shape><shape h="32.0" w="40.0" aspect="variable" strokewidth="inherit" name="valve_horizontal" displayName="valve_horizontal">
|
| 2351 |
+
<foreground>
|
| 2352 |
+
<rect x="8" y="0.53" w="24" h="9.28" />
|
| 2353 |
+
<fillstroke />
|
| 2354 |
+
<stroke />
|
| 2355 |
+
<path>
|
| 2356 |
+
<move x="0" y="7.88" />
|
| 2357 |
+
<line x="20" y="19.94" />
|
| 2358 |
+
<line x="0" y="32.0" />
|
| 2359 |
+
<close />
|
| 2360 |
+
<move x="40" y="7.88" />
|
| 2361 |
+
<line x="20" y="19.94" />
|
| 2362 |
+
<line x="40" y="32.0" />
|
| 2363 |
+
<close />
|
| 2364 |
+
</path>
|
| 2365 |
+
<fillstroke />
|
| 2366 |
+
<stroke />
|
| 2367 |
+
<path>
|
| 2368 |
+
<move x="20" y="18.03" />
|
| 2369 |
+
<line x="20" y="9.81" />
|
| 2370 |
+
</path>
|
| 2371 |
+
<stroke />
|
| 2372 |
+
<path>
|
| 2373 |
+
<move x="20" y="19.5" />
|
| 2374 |
+
<line x="20" y="18.03" />
|
| 2375 |
+
</path>
|
| 2376 |
+
<stroke />
|
| 2377 |
+
</foreground>
|
| 2378 |
+
</shape><shape h="40.0" w="32.0" aspect="variable" strokewidth="inherit" name="valve_vertical" displayName="valve_vertical">
|
| 2379 |
+
<foreground>
|
| 2380 |
+
<path>
|
| 2381 |
+
<move x="31.409999999999997" y="8.239999999999998" />
|
| 2382 |
+
<line x="31.41" y="32.239999999999995" />
|
| 2383 |
+
<line x="22.13" y="32.239999999999995" />
|
| 2384 |
+
<line x="22.13" y="8.239999999999998" />
|
| 2385 |
+
<close />
|
| 2386 |
+
</path>
|
| 2387 |
+
<fillstroke />
|
| 2388 |
+
<stroke />
|
| 2389 |
+
<path>
|
| 2390 |
+
<move x="24.059999999999995" y="0.23999999999999844" />
|
| 2391 |
+
<line x="12.0" y="20.24" />
|
| 2392 |
+
<line x="-0.0600000000000005" y="0.23999999999999844" />
|
| 2393 |
+
<close />
|
| 2394 |
+
<move x="24.060000000000002" y="40.239999999999995" />
|
| 2395 |
+
<line x="12.0" y="20.24" />
|
| 2396 |
+
<line x="-0.059999999999996945" y="40.239999999999995" />
|
| 2397 |
+
<close />
|
| 2398 |
+
</path>
|
| 2399 |
+
<fillstroke />
|
| 2400 |
+
<stroke />
|
| 2401 |
+
<path>
|
| 2402 |
+
<move x="12.12" y="20.16" />
|
| 2403 |
+
<line x="22.13" y="20.24" />
|
| 2404 |
+
</path>
|
| 2405 |
+
<stroke />
|
| 2406 |
+
</foreground>
|
| 2407 |
+
</shape><shape h="250.0" w="78.0" aspect="variable" strokewidth="inherit" name="vertical_apparatus" displayName="vertical_apparatus"><foreground><rect x="0" y="0" w="77.83" h="179.25" /><fillstroke /><stroke /><path><move x="40.08999999999999" y="179.24" /><line x="20.050000000000004" y="249.99" /><line x="1.4210854715202004e-14" y="179.24" /><close /></path><fillstroke /><stroke /><path><move x="77.82000000000001" y="179.25" /><line x="58.37" y="250.0" /><line x="38.90999999999998" y="179.25" /><close /></path><fillstroke /><stroke /></foreground></shape></shapes>
|
mnemo-studio-tool/web/Widget.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
web-new/src/App.css
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
.app-shell {
|
| 2 |
display: grid;
|
| 3 |
grid-template-rows: auto 1fr;
|
|
|
|
| 4 |
min-height: 100%;
|
| 5 |
background:
|
| 6 |
radial-gradient(circle at top left, rgba(14, 165, 164, 0.14), transparent 34%),
|
|
@@ -71,11 +72,13 @@
|
|
| 71 |
|
| 72 |
.main-content {
|
| 73 |
display: grid;
|
|
|
|
| 74 |
overflow: hidden;
|
| 75 |
}
|
| 76 |
|
| 77 |
.editor-layout {
|
| 78 |
-
grid-template-columns: minmax(0, 1fr)
|
|
|
|
| 79 |
}
|
| 80 |
|
| 81 |
.workspace-stack {
|
|
@@ -174,6 +177,7 @@
|
|
| 174 |
|
| 175 |
.sidebar {
|
| 176 |
min-width: 0;
|
|
|
|
| 177 |
overflow-y: auto;
|
| 178 |
overflow-x: hidden;
|
| 179 |
display: flex;
|
|
@@ -186,6 +190,7 @@
|
|
| 186 |
|
| 187 |
.panel-section {
|
| 188 |
min-width: 0;
|
|
|
|
| 189 |
padding: 16px;
|
| 190 |
border-radius: 16px;
|
| 191 |
background: linear-gradient(180deg, rgba(30, 41, 59, 0.94), rgba(15, 23, 42, 0.94));
|
|
@@ -197,11 +202,14 @@
|
|
| 197 |
display: flex;
|
| 198 |
align-items: center;
|
| 199 |
justify-content: space-between;
|
|
|
|
| 200 |
gap: 10px;
|
| 201 |
margin-bottom: 14px;
|
| 202 |
}
|
| 203 |
|
| 204 |
.panel-head h2 {
|
|
|
|
|
|
|
| 205 |
font-size: 15px;
|
| 206 |
font-weight: 650;
|
| 207 |
}
|
|
@@ -209,6 +217,7 @@
|
|
| 209 |
.panel-note {
|
| 210 |
color: var(--text-muted);
|
| 211 |
font-size: 11px;
|
|
|
|
| 212 |
}
|
| 213 |
|
| 214 |
.panel-grid {
|
|
@@ -314,11 +323,15 @@
|
|
| 314 |
}
|
| 315 |
|
| 316 |
.xml-preview-section {
|
|
|
|
|
|
|
| 317 |
min-height: 260px;
|
| 318 |
}
|
| 319 |
|
| 320 |
.xml-preview {
|
|
|
|
| 321 |
width: 100%;
|
|
|
|
| 322 |
min-height: 220px;
|
| 323 |
resize: vertical;
|
| 324 |
border: 1px solid rgba(148, 163, 184, 0.18);
|
|
@@ -456,8 +469,9 @@
|
|
| 456 |
|
| 457 |
.inspector-panel {
|
| 458 |
display: flex;
|
|
|
|
| 459 |
flex-direction: column;
|
| 460 |
-
min-height:
|
| 461 |
overflow: hidden;
|
| 462 |
}
|
| 463 |
|
|
@@ -479,6 +493,15 @@
|
|
| 479 |
font-weight: 600;
|
| 480 |
}
|
| 481 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 482 |
.inspector-editor {
|
| 483 |
padding-bottom: 12px;
|
| 484 |
margin-bottom: 10px;
|
|
@@ -591,6 +614,26 @@
|
|
| 591 |
font-weight: 600;
|
| 592 |
}
|
| 593 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 594 |
.ann-meta {
|
| 595 |
display: flex;
|
| 596 |
flex-wrap: wrap;
|
|
|
|
| 1 |
.app-shell {
|
| 2 |
display: grid;
|
| 3 |
grid-template-rows: auto 1fr;
|
| 4 |
+
height: 100%;
|
| 5 |
min-height: 100%;
|
| 6 |
background:
|
| 7 |
radial-gradient(circle at top left, rgba(14, 165, 164, 0.14), transparent 34%),
|
|
|
|
| 72 |
|
| 73 |
.main-content {
|
| 74 |
display: grid;
|
| 75 |
+
min-height: 0;
|
| 76 |
overflow: hidden;
|
| 77 |
}
|
| 78 |
|
| 79 |
.editor-layout {
|
| 80 |
+
grid-template-columns: 200px minmax(0, 1fr) 380px;
|
| 81 |
+
min-height: 0;
|
| 82 |
}
|
| 83 |
|
| 84 |
.workspace-stack {
|
|
|
|
| 177 |
|
| 178 |
.sidebar {
|
| 179 |
min-width: 0;
|
| 180 |
+
min-height: 0;
|
| 181 |
overflow-y: auto;
|
| 182 |
overflow-x: hidden;
|
| 183 |
display: flex;
|
|
|
|
| 190 |
|
| 191 |
.panel-section {
|
| 192 |
min-width: 0;
|
| 193 |
+
flex-shrink: 0;
|
| 194 |
padding: 16px;
|
| 195 |
border-radius: 16px;
|
| 196 |
background: linear-gradient(180deg, rgba(30, 41, 59, 0.94), rgba(15, 23, 42, 0.94));
|
|
|
|
| 202 |
display: flex;
|
| 203 |
align-items: center;
|
| 204 |
justify-content: space-between;
|
| 205 |
+
flex-wrap: wrap;
|
| 206 |
gap: 10px;
|
| 207 |
margin-bottom: 14px;
|
| 208 |
}
|
| 209 |
|
| 210 |
.panel-head h2 {
|
| 211 |
+
margin: 0;
|
| 212 |
+
min-width: 0;
|
| 213 |
font-size: 15px;
|
| 214 |
font-weight: 650;
|
| 215 |
}
|
|
|
|
| 217 |
.panel-note {
|
| 218 |
color: var(--text-muted);
|
| 219 |
font-size: 11px;
|
| 220 |
+
flex-shrink: 0;
|
| 221 |
}
|
| 222 |
|
| 223 |
.panel-grid {
|
|
|
|
| 323 |
}
|
| 324 |
|
| 325 |
.xml-preview-section {
|
| 326 |
+
display: flex;
|
| 327 |
+
flex-direction: column;
|
| 328 |
min-height: 260px;
|
| 329 |
}
|
| 330 |
|
| 331 |
.xml-preview {
|
| 332 |
+
flex: 1 1 auto;
|
| 333 |
width: 100%;
|
| 334 |
+
min-width: 0;
|
| 335 |
min-height: 220px;
|
| 336 |
resize: vertical;
|
| 337 |
border: 1px solid rgba(148, 163, 184, 0.18);
|
|
|
|
| 469 |
|
| 470 |
.inspector-panel {
|
| 471 |
display: flex;
|
| 472 |
+
flex: 1 0 320px;
|
| 473 |
flex-direction: column;
|
| 474 |
+
min-height: 320px;
|
| 475 |
overflow: hidden;
|
| 476 |
}
|
| 477 |
|
|
|
|
| 493 |
font-weight: 600;
|
| 494 |
}
|
| 495 |
|
| 496 |
+
.inspector-meta.xml-ok {
|
| 497 |
+
color: #86efac;
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
.inspector-meta.xml-warn {
|
| 501 |
+
color: #fbbf24;
|
| 502 |
+
font-weight: 600;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
.inspector-editor {
|
| 506 |
padding-bottom: 12px;
|
| 507 |
margin-bottom: 10px;
|
|
|
|
| 614 |
font-weight: 600;
|
| 615 |
}
|
| 616 |
|
| 617 |
+
.ann-xml-status {
|
| 618 |
+
display: inline-flex;
|
| 619 |
+
align-items: center;
|
| 620 |
+
margin-left: auto;
|
| 621 |
+
padding: 2px 6px;
|
| 622 |
+
border-radius: 999px;
|
| 623 |
+
font-size: 10px;
|
| 624 |
+
font-weight: 700;
|
| 625 |
+
}
|
| 626 |
+
|
| 627 |
+
.ann-xml-status.ok {
|
| 628 |
+
background: rgba(34, 197, 94, 0.14);
|
| 629 |
+
color: #86efac;
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
.ann-xml-status.warn {
|
| 633 |
+
background: rgba(245, 158, 11, 0.16);
|
| 634 |
+
color: #fbbf24;
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
.ann-meta {
|
| 638 |
display: flex;
|
| 639 |
flex-wrap: wrap;
|
web-new/src/App.jsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import { useCallback, useMemo, useRef, useState } from 'react';
|
| 2 |
import './App.css';
|
| 3 |
import { analyzeLayout, generateImportXml, runOcr } from './api';
|
|
|
|
| 4 |
import ImageUpload from './components/ImageUpload';
|
| 5 |
import Inspector from './components/Inspector';
|
| 6 |
import SvgWorkspace from './components/SvgWorkspace';
|
|
@@ -10,7 +11,7 @@ import { useKeyboard } from './hooks/useKeyboard';
|
|
| 10 |
import * as A from './store/actions';
|
| 11 |
import { useDispatch, useStore } from './store/context';
|
| 12 |
import { baseName, downloadText, fileToDataUrl } from './utils/files';
|
| 13 |
-
import { boundsOfPoints, rectToPoints } from './utils/geometry';
|
| 14 |
import { uid } from './utils/uid';
|
| 15 |
|
| 16 |
|
|
@@ -27,6 +28,7 @@ const UID_TRANSLATION = {
|
|
| 27 |
};
|
| 28 |
|
| 29 |
const STRICT_UID_RE = /^(?:N|NO|№)?\s*\d{1,4}$/i;
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
function loadImageElement(dataUrl) {
|
|
@@ -44,6 +46,12 @@ function normalizeBindingUid(value) {
|
|
| 44 |
if (!text) return '';
|
| 45 |
const translated = Array.from(text, (char) => UID_TRANSLATION[char] ?? char).join('');
|
| 46 |
const compact = translated.replace(/\s+/g, '');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
if (/[.,;:]/.test(compact)) return '';
|
| 48 |
if (!STRICT_UID_RE.test(compact)) return '';
|
| 49 |
const digits = translated.replace(/\D+/g, '');
|
|
@@ -77,6 +85,7 @@ function buildAnnotationPayload(annotation) {
|
|
| 77 |
return {
|
| 78 |
id: annotation.id,
|
| 79 |
number: annotation.number,
|
|
|
|
| 80 |
bindingUid: explicitBindingUid,
|
| 81 |
detectedKind: annotation.detectedKind || '',
|
| 82 |
type: annotation.type || 'rect',
|
|
@@ -97,15 +106,54 @@ function buildAnnotationPayload(annotation) {
|
|
| 97 |
}
|
| 98 |
|
| 99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
function detectedKindFromDetectionItem(annotation) {
|
| 101 |
const explicitKind = String(annotation?.detectedKind || annotation?.kind || '').trim().toLowerCase();
|
| 102 |
if (explicitKind && explicitKind !== 'other') return explicitKind;
|
| 103 |
const category = String(annotation?.category || '').trim().toLowerCase();
|
| 104 |
-
if (category === '
|
| 105 |
-
if (category === '
|
|
|
|
|
|
|
| 106 |
if (category === 'pipe') return 'arrow';
|
| 107 |
-
if (category === 'equipment') return '
|
| 108 |
if (category === 'indicator') return 'indicator';
|
|
|
|
| 109 |
return explicitKind || 'other';
|
| 110 |
}
|
| 111 |
|
|
@@ -135,28 +183,38 @@ function buildAutoAnnotationsFromDetectionItems(items, existingAnnotations) {
|
|
| 135 |
const validPoints = item.points
|
| 136 |
.map((point) => ({ x: Number(point?.x) || 0, y: Number(point?.y) || 0 }))
|
| 137 |
.filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y));
|
|
|
|
|
|
|
| 138 |
const bounds = boundsOfPoints(validPoints);
|
| 139 |
const x = Number(bounds.x) || 0;
|
| 140 |
const y = Number(bounds.y) || 0;
|
| 141 |
const width = Math.max(1, Number(bounds.width) || 0);
|
| 142 |
const height = Math.max(1, Number(bounds.height) || 0);
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
usedNumbers.add(number);
|
| 148 |
|
| 149 |
-
const type = item?.type === '
|
| 150 |
-
?
|
| 151 |
-
: 'rect';
|
| 152 |
const points = type === 'polygon'
|
| 153 |
-
?
|
| 154 |
: rectToPoints({ x, y, width, height });
|
| 155 |
const bindingUid = normalizeBindingUid(item?.bindingUid);
|
| 156 |
|
| 157 |
created.push({
|
| 158 |
id: uid('ann'),
|
| 159 |
number,
|
|
|
|
| 160 |
bindingUid,
|
| 161 |
detectedKind: kind,
|
| 162 |
type,
|
|
@@ -183,11 +241,13 @@ function formatDetectionCounts(counts) {
|
|
| 183 |
const safe = counts || {};
|
| 184 |
const parts = [`всего ${Number(safe.total) || 0}`];
|
| 185 |
const metrics = [
|
| 186 |
-
['
|
| 187 |
-
['
|
|
|
|
|
|
|
| 188 |
['стрелки', Number(safe.arrows) || 0],
|
|
|
|
| 189 |
['ocr-ячейки', Number(safe.ocrCells) || 0],
|
| 190 |
-
['оборудование', Number(safe.equipment) || 0],
|
| 191 |
['индикаторы', Number(safe.indicators) || 0],
|
| 192 |
['прочее', Number(safe.other) || 0],
|
| 193 |
];
|
|
@@ -211,8 +271,8 @@ function formatSheetReason(reason) {
|
|
| 211 |
}
|
| 212 |
|
| 213 |
|
| 214 |
-
const AUTO_DETECTOR_MODE = '
|
| 215 |
-
const AUTO_DETECTOR_LABEL = 'src-
|
| 216 |
|
| 217 |
|
| 218 |
function AppShell() {
|
|
@@ -220,6 +280,7 @@ function AppShell() {
|
|
| 220 |
const dispatch = useDispatch();
|
| 221 |
const fileInputRef = useRef(null);
|
| 222 |
const [errorText, setErrorText] = useState('');
|
|
|
|
| 223 |
|
| 224 |
const {
|
| 225 |
deleteSelected,
|
|
@@ -231,6 +292,10 @@ function AppShell() {
|
|
| 231 |
() => state.annotations.find((annotation) => annotation.id === state.selectedId) || null,
|
| 232 |
[state.annotations, state.selectedId],
|
| 233 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
|
| 235 |
const setStatus = useCallback((text) => {
|
| 236 |
dispatch({ type: A.SET_STATUS, payload: text });
|
|
@@ -270,11 +335,12 @@ function AppShell() {
|
|
| 270 |
dispatch({
|
| 271 |
type: A.SET_PROCESSING,
|
| 272 |
payload: {
|
|
|
|
| 273 |
ready: false,
|
| 274 |
components: [],
|
| 275 |
counts: {},
|
| 276 |
summary: '',
|
| 277 |
-
detector:
|
| 278 |
lastAnalyzedAt: '',
|
| 279 |
},
|
| 280 |
});
|
|
@@ -309,6 +375,7 @@ function AppShell() {
|
|
| 309 |
if (!state.imageDataUrl || !selectedAnnotation) return;
|
| 310 |
|
| 311 |
try {
|
|
|
|
| 312 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 313 |
setErrorText('');
|
| 314 |
const bounds = annotationBounds(selectedAnnotation);
|
|
@@ -342,6 +409,7 @@ function AppShell() {
|
|
| 342 |
} catch (error) {
|
| 343 |
setErrorText(error.message || 'OCR для выделенного элемента завершился ошибкой.');
|
| 344 |
} finally {
|
|
|
|
| 345 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 346 |
}
|
| 347 |
}, [dispatch, selectedAnnotation, setStatus, state.imageDataUrl]);
|
|
@@ -350,13 +418,29 @@ function AppShell() {
|
|
| 350 |
if (!state.imageDataUrl) return;
|
| 351 |
|
| 352 |
try {
|
|
|
|
| 353 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 354 |
setErrorText('');
|
| 355 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
const result = await analyzeLayout({
|
| 357 |
imageDataUrl: state.imageDataUrl,
|
| 358 |
config: {
|
| 359 |
detectorMode: AUTO_DETECTOR_MODE,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
sensitivity: state.config.sensitivity,
|
| 361 |
imageCorrection: state.config.imageCorrection,
|
| 362 |
enhanceImage: state.config.enhanceImage,
|
|
@@ -364,11 +448,23 @@ function AppShell() {
|
|
| 364 |
},
|
| 365 |
});
|
| 366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 367 |
const manualAnnotations = state.annotations.filter((annotation) => annotation.source !== 'auto');
|
| 368 |
const created = buildAutoAnnotationsFromDetectionItems(result.overlays, manualAnnotations);
|
|
|
|
| 369 |
dispatch({
|
| 370 |
type: A.SET_PROCESSING,
|
| 371 |
payload: {
|
|
|
|
| 372 |
ready: true,
|
| 373 |
width: Number(result.imageWidth) || state.imageWidth,
|
| 374 |
height: Number(result.imageHeight) || state.imageHeight,
|
|
@@ -376,7 +472,7 @@ function AppShell() {
|
|
| 376 |
components: Array.isArray(result.overlays) ? result.overlays : [],
|
| 377 |
counts: result.counts || {},
|
| 378 |
summary: result.summary || '',
|
| 379 |
-
detector: result.engine || 'src-
|
| 380 |
lastAnalyzedAt: new Date().toISOString(),
|
| 381 |
},
|
| 382 |
});
|
|
@@ -395,8 +491,18 @@ function AppShell() {
|
|
| 395 |
dispatch({ type: A.SELECT_ANNOTATION, payload: created[0].id });
|
| 396 |
setStatus(`${result.summary || 'Автораспознавание завершено.'} Создано автоаннотаций: ${created.length}.`);
|
| 397 |
} catch (error) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
setErrorText(error.message || 'Автораспознавание завершилось ошибкой.');
|
| 399 |
} finally {
|
|
|
|
| 400 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 401 |
}
|
| 402 |
}, [dispatch, setStatus, setWidgetExport, state.annotations, state.config.enhanceImage, state.config.ignoreLines, state.config.imageCorrection, state.config.sensitivity, state.imageDataUrl, state.imageHeight, state.imageWidth]);
|
|
@@ -408,10 +514,12 @@ function AppShell() {
|
|
| 408 |
dispatch({
|
| 409 |
type: A.SET_PROCESSING,
|
| 410 |
payload: {
|
|
|
|
| 411 |
ready: false,
|
| 412 |
components: [],
|
| 413 |
counts: {},
|
| 414 |
summary: '',
|
|
|
|
| 415 |
lastAnalyzedAt: '',
|
| 416 |
},
|
| 417 |
});
|
|
@@ -428,38 +536,18 @@ function AppShell() {
|
|
| 428 |
dispatch({
|
| 429 |
type: A.SET_PROCESSING,
|
| 430 |
payload: {
|
|
|
|
| 431 |
ready: false,
|
| 432 |
components: [],
|
| 433 |
counts: {},
|
| 434 |
summary: '',
|
|
|
|
| 435 |
lastAnalyzedAt: '',
|
| 436 |
},
|
| 437 |
});
|
| 438 |
setStatus('Автоматические аннотации удалены.');
|
| 439 |
}, [dispatch, setStatus, state.annotations, state.processing]);
|
| 440 |
|
| 441 |
-
const applyResolvedBindings = useCallback((bindings) => {
|
| 442 |
-
if (!Array.isArray(bindings) || !bindings.length) return;
|
| 443 |
-
const bindingsByUid = new Map();
|
| 444 |
-
bindings.forEach((binding) => {
|
| 445 |
-
const key = normalizeBindingUid(binding.uid);
|
| 446 |
-
if (key && !bindingsByUid.has(key)) bindingsByUid.set(key, binding);
|
| 447 |
-
});
|
| 448 |
-
|
| 449 |
-
const nextAnnotations = state.annotations.map((annotation) => {
|
| 450 |
-
const key = normalizeBindingUid(annotation.bindingUid);
|
| 451 |
-
const binding = bindingsByUid.get(key);
|
| 452 |
-
if (!binding) return annotation;
|
| 453 |
-
return {
|
| 454 |
-
...annotation,
|
| 455 |
-
contextPath: annotation.contextPath || binding.omPath || '',
|
| 456 |
-
widgetNameOverride: annotation.widgetNameOverride || binding.widget || '',
|
| 457 |
-
};
|
| 458 |
-
});
|
| 459 |
-
|
| 460 |
-
dispatch({ type: A.SET_ANNOTATIONS, payload: nextAnnotations });
|
| 461 |
-
}, [dispatch, state.annotations]);
|
| 462 |
-
|
| 463 |
const handleGenerateImport = useCallback(async () => {
|
| 464 |
if (!state.imageDataUrl || !state.annotations.length) {
|
| 465 |
setErrorText('Сначала загрузите изображение и создайте или проверьте аннотации элементов схемы.');
|
|
@@ -467,6 +555,7 @@ function AppShell() {
|
|
| 467 |
}
|
| 468 |
|
| 469 |
try {
|
|
|
|
| 470 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 471 |
setErrorText('');
|
| 472 |
setStatus('Генерация import XML...');
|
|
@@ -481,7 +570,12 @@ function AppShell() {
|
|
| 481 |
excelPath: state.widgetExport.excelPath || undefined,
|
| 482 |
});
|
| 483 |
|
| 484 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 485 |
setWidgetExport({
|
| 486 |
generatedXmlText: result.xmlText,
|
| 487 |
mnemoTitle: result.title || state.widgetExport.mnemoTitle,
|
|
@@ -492,6 +586,7 @@ function AppShell() {
|
|
| 492 |
exportedCount: result.exportedCount,
|
| 493 |
unmatchedNumbers: result.unmatchedNumbers || [],
|
| 494 |
missingVisuals: result.missingVisuals || [],
|
|
|
|
| 495 |
lastGeneratedAt: new Date().toISOString(),
|
| 496 |
});
|
| 497 |
setStatus(
|
|
@@ -500,9 +595,10 @@ function AppShell() {
|
|
| 500 |
} catch (error) {
|
| 501 |
setErrorText(error.message || 'Не удалось сформировать import XML.');
|
| 502 |
} finally {
|
|
|
|
| 503 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 504 |
}
|
| 505 |
-
}, [
|
| 506 |
|
| 507 |
const handleDownloadXml = useCallback(() => {
|
| 508 |
const xmlText = String(state.widgetExport.generatedXmlText || '').trim();
|
|
@@ -514,6 +610,51 @@ function AppShell() {
|
|
| 514 |
downloadText(xmlText, defaultName, 'application/xml;charset=utf-8');
|
| 515 |
}, [state.imageName, state.widgetExport.generatedXmlText, state.widgetExport.sheetResolvedName]);
|
| 516 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 517 |
useKeyboard({
|
| 518 |
onUndo: () => dispatch({ type: A.UNDO }),
|
| 519 |
onRedo: () => dispatch({ type: A.REDO }),
|
|
@@ -570,19 +711,19 @@ function AppShell() {
|
|
| 570 |
</button>
|
| 571 |
{hasImage && (
|
| 572 |
<>
|
| 573 |
-
<button className="btn btn-warn" onClick={handleAutoDetect} disabled={
|
| 574 |
-
{
|
| 575 |
</button>
|
| 576 |
-
<button className="btn btn-ghost" onClick={handleSelectedOcr} disabled={!selectedAnnotation ||
|
| 577 |
-
OCR выделенного
|
| 578 |
</button>
|
| 579 |
-
<button className="btn btn-primary" onClick={handleGenerateImport} disabled={!state.annotations.length ||
|
| 580 |
-
{
|
| 581 |
</button>
|
| 582 |
<button className="btn btn-success" onClick={handleDownloadXml} disabled={!hasGeneratedXml}>
|
| 583 |
Скачать XML
|
| 584 |
</button>
|
| 585 |
-
<button className="btn btn-ghost" onClick={handleReset} disabled={
|
| 586 |
Сбросить
|
| 587 |
</button>
|
| 588 |
</>
|
|
@@ -595,13 +736,14 @@ function AppShell() {
|
|
| 595 |
<ImageUpload onImageLoad={handleImageLoad} />
|
| 596 |
<div className="empty-hints">
|
| 597 |
<h3>Что умеет новая реализация</h3>
|
| 598 |
-
<p>Кнопка `Автораспознавание` запускает
|
| 599 |
-
<p>
|
| 600 |
<p>Файл Приложения сервер найдёт автоматически в проекте. При необходимости путь можно переопределить после загрузки изображения.</p>
|
| 601 |
</div>
|
| 602 |
</div>
|
| 603 |
) : (
|
| 604 |
<div className="main-content editor-layout">
|
|
|
|
| 605 |
<section className="workspace-stack">
|
| 606 |
<Toolbar
|
| 607 |
onUndo={() => dispatch({ type: A.UNDO })}
|
|
@@ -619,7 +761,7 @@ function AppShell() {
|
|
| 619 |
<span className="panel-note">
|
| 620 |
{state.processing.lastAnalyzedAt
|
| 621 |
? new Date(state.processing.lastAnalyzedAt).toLocaleString()
|
| 622 |
-
: 'ещё не запускалось'}
|
| 623 |
</span>
|
| 624 |
</div>
|
| 625 |
|
|
@@ -630,7 +772,13 @@ function AppShell() {
|
|
| 630 |
</div>
|
| 631 |
<div className="summary-item">
|
| 632 |
<span>Сводка</span>
|
| 633 |
-
<strong>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 634 |
</div>
|
| 635 |
</div>
|
| 636 |
|
|
@@ -695,8 +843,8 @@ function AppShell() {
|
|
| 695 |
</div>
|
| 696 |
|
| 697 |
<div className="panel-actions">
|
| 698 |
-
<button className="btn btn-primary" onClick={handleGenerateImport} disabled={!state.annotations.length ||
|
| 699 |
-
{
|
| 700 |
</button>
|
| 701 |
<button className="btn btn-success" onClick={handleDownloadXml} disabled={!hasGeneratedXml}>
|
| 702 |
Скачать
|
|
@@ -741,20 +889,9 @@ function AppShell() {
|
|
| 741 |
)}
|
| 742 |
</section>
|
| 743 |
|
| 744 |
-
|
| 745 |
|
| 746 |
-
<
|
| 747 |
-
<div className="panel-head">
|
| 748 |
-
<h2>XML Preview</h2>
|
| 749 |
-
<span className="panel-note">{hasGeneratedXml ? `${state.widgetExport.generatedXmlText.length} символов` : 'пусто'}</span>
|
| 750 |
-
</div>
|
| 751 |
-
<textarea
|
| 752 |
-
className="xml-preview"
|
| 753 |
-
readOnly
|
| 754 |
-
value={state.widgetExport.generatedXmlText || ''}
|
| 755 |
-
placeholder="После генерации здесь появится import XML."
|
| 756 |
-
/>
|
| 757 |
-
</section>
|
| 758 |
</aside>
|
| 759 |
</div>
|
| 760 |
)}
|
|
|
|
| 1 |
import { useCallback, useMemo, useRef, useState } from 'react';
|
| 2 |
import './App.css';
|
| 3 |
import { analyzeLayout, generateImportXml, runOcr } from './api';
|
| 4 |
+
import ElementLibraryPanel from './components/ElementLibraryPanel';
|
| 5 |
import ImageUpload from './components/ImageUpload';
|
| 6 |
import Inspector from './components/Inspector';
|
| 7 |
import SvgWorkspace from './components/SvgWorkspace';
|
|
|
|
| 11 |
import * as A from './store/actions';
|
| 12 |
import { useDispatch, useStore } from './store/context';
|
| 13 |
import { baseName, downloadText, fileToDataUrl } from './utils/files';
|
| 14 |
+
import { boundsOfPoints, rectToPoints, isLikelyRect, simplifyClosedPolygon, dedupeClosePoints } from './utils/geometry';
|
| 15 |
import { uid } from './utils/uid';
|
| 16 |
|
| 17 |
|
|
|
|
| 28 |
};
|
| 29 |
|
| 30 |
const STRICT_UID_RE = /^(?:N|NO|№)?\s*\d{1,4}$/i;
|
| 31 |
+
const COMPOSITE_UID_RE = /^(?:N|NO|№)?\s*(\d{1,4})\.(\d{1,2})$/i;
|
| 32 |
|
| 33 |
|
| 34 |
function loadImageElement(dataUrl) {
|
|
|
|
| 46 |
if (!text) return '';
|
| 47 |
const translated = Array.from(text, (char) => UID_TRANSLATION[char] ?? char).join('');
|
| 48 |
const compact = translated.replace(/\s+/g, '');
|
| 49 |
+
const compositeMatch = compact.match(COMPOSITE_UID_RE);
|
| 50 |
+
if (compositeMatch) {
|
| 51 |
+
const baseDigits = compositeMatch[1].replace(/^0+/, '') || compositeMatch[1];
|
| 52 |
+
const suffixDigits = compositeMatch[2].replace(/^0+/, '') || compositeMatch[2];
|
| 53 |
+
return `${baseDigits}.${suffixDigits}`;
|
| 54 |
+
}
|
| 55 |
if (/[.,;:]/.test(compact)) return '';
|
| 56 |
if (!STRICT_UID_RE.test(compact)) return '';
|
| 57 |
const digits = translated.replace(/\D+/g, '');
|
|
|
|
| 85 |
return {
|
| 86 |
id: annotation.id,
|
| 87 |
number: annotation.number,
|
| 88 |
+
displayNumber: annotation.displayNumber ?? null,
|
| 89 |
bindingUid: explicitBindingUid,
|
| 90 |
detectedKind: annotation.detectedKind || '',
|
| 91 |
type: annotation.type || 'rect',
|
|
|
|
| 106 |
}
|
| 107 |
|
| 108 |
|
| 109 |
+
function mergeImportResultsIntoAnnotations(annotations, bindings, annotationResults) {
|
| 110 |
+
const bindingsByUid = new Map();
|
| 111 |
+
if (Array.isArray(bindings)) {
|
| 112 |
+
bindings.forEach((binding) => {
|
| 113 |
+
const key = normalizeBindingUid(binding?.uid);
|
| 114 |
+
if (key && !bindingsByUid.has(key)) bindingsByUid.set(key, binding);
|
| 115 |
+
});
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
const resultsById = new Map();
|
| 119 |
+
if (Array.isArray(annotationResults)) {
|
| 120 |
+
annotationResults.forEach((item) => {
|
| 121 |
+
const id = String(item?.id || '').trim();
|
| 122 |
+
if (id) resultsById.set(id, item);
|
| 123 |
+
});
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
return (Array.isArray(annotations) ? annotations : []).map((annotation) => {
|
| 127 |
+
const key = normalizeBindingUid(annotation.bindingUid);
|
| 128 |
+
const binding = bindingsByUid.get(key);
|
| 129 |
+
const result = resultsById.get(annotation.id);
|
| 130 |
+
return {
|
| 131 |
+
...annotation,
|
| 132 |
+
contextPath: annotation.contextPath || binding?.omPath || '',
|
| 133 |
+
widgetNameOverride: annotation.widgetNameOverride || binding?.widget || '',
|
| 134 |
+
xmlStatus: String(result?.status || '').trim(),
|
| 135 |
+
xmlMatched: Boolean(result?.matched),
|
| 136 |
+
xmlExported: Boolean(result?.exported),
|
| 137 |
+
xmlNeedsAttention: Boolean(result?.needsAttention),
|
| 138 |
+
xmlMissingVisuals: Array.isArray(result?.missingVisuals) ? result.missingVisuals : [],
|
| 139 |
+
xmlResolvedVisuals: Array.isArray(result?.resolvedVisuals) ? result.resolvedVisuals : [],
|
| 140 |
+
};
|
| 141 |
+
});
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
|
| 145 |
function detectedKindFromDetectionItem(annotation) {
|
| 146 |
const explicitKind = String(annotation?.detectedKind || annotation?.kind || '').trim().toLowerCase();
|
| 147 |
if (explicitKind && explicitKind !== 'other') return explicitKind;
|
| 148 |
const category = String(annotation?.category || '').trim().toLowerCase();
|
| 149 |
+
if (category === 'widget') return 'widget';
|
| 150 |
+
if (category === 'static') return 'form';
|
| 151 |
+
if (category === 'table') return 'form';
|
| 152 |
+
if (category === 'value') return 'widget';
|
| 153 |
if (category === 'pipe') return 'arrow';
|
| 154 |
+
if (category === 'equipment') return 'shape';
|
| 155 |
if (category === 'indicator') return 'indicator';
|
| 156 |
+
if (category === 'text') return explicitKind || 'text-label';
|
| 157 |
return explicitKind || 'other';
|
| 158 |
}
|
| 159 |
|
|
|
|
| 183 |
const validPoints = item.points
|
| 184 |
.map((point) => ({ x: Number(point?.x) || 0, y: Number(point?.y) || 0 }))
|
| 185 |
.filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y));
|
| 186 |
+
const reducedPoints = simplifyClosedPolygon(dedupeClosePoints(validPoints, 1.2), 1.4);
|
| 187 |
+
const shapePoints = reducedPoints.length >= 3 ? reducedPoints : validPoints;
|
| 188 |
const bounds = boundsOfPoints(validPoints);
|
| 189 |
const x = Number(bounds.x) || 0;
|
| 190 |
const y = Number(bounds.y) || 0;
|
| 191 |
const width = Math.max(1, Number(bounds.width) || 0);
|
| 192 |
const height = Math.max(1, Number(bounds.height) || 0);
|
| 193 |
+
const rawDisplayNumber = Number.parseInt(String(item?.displayNumber ?? item?.number ?? ''), 10);
|
| 194 |
+
const displayNumber = Number.isFinite(rawDisplayNumber) && rawDisplayNumber > 0
|
| 195 |
+
? rawDisplayNumber
|
| 196 |
+
: null;
|
| 197 |
+
|
| 198 |
+
let number = displayNumber;
|
| 199 |
+
if (!Number.isFinite(number) || usedNumbers.has(number)) {
|
| 200 |
+
while (usedNumbers.has(fallbackNumber)) fallbackNumber += 1;
|
| 201 |
+
number = fallbackNumber;
|
| 202 |
+
fallbackNumber += 1;
|
| 203 |
+
}
|
| 204 |
usedNumbers.add(number);
|
| 205 |
|
| 206 |
+
const type = item?.type === 'rect'
|
| 207 |
+
? 'rect'
|
| 208 |
+
: (shapePoints.length >= 3 && !isLikelyRect(shapePoints) ? 'polygon' : 'rect');
|
| 209 |
const points = type === 'polygon'
|
| 210 |
+
? shapePoints
|
| 211 |
: rectToPoints({ x, y, width, height });
|
| 212 |
const bindingUid = normalizeBindingUid(item?.bindingUid);
|
| 213 |
|
| 214 |
created.push({
|
| 215 |
id: uid('ann'),
|
| 216 |
number,
|
| 217 |
+
displayNumber,
|
| 218 |
bindingUid,
|
| 219 |
detectedKind: kind,
|
| 220 |
type,
|
|
|
|
| 241 |
const safe = counts || {};
|
| 242 |
const parts = [`всего ${Number(safe.total) || 0}`];
|
| 243 |
const metrics = [
|
| 244 |
+
['виджеты', Number(safe.widgets) || Number(safe.cells) || 0],
|
| 245 |
+
['статика', Number(safe.statics) || 0],
|
| 246 |
+
['формы', Number(safe.forms) || Number(safe.groups) || 0],
|
| 247 |
+
['шейпы', Number(safe.shapes) || Number(safe.equipment) || 0],
|
| 248 |
['стрелки', Number(safe.arrows) || 0],
|
| 249 |
+
['текст', Number(safe.text) || 0],
|
| 250 |
['ocr-ячейки', Number(safe.ocrCells) || 0],
|
|
|
|
| 251 |
['индикаторы', Number(safe.indicators) || 0],
|
| 252 |
['прочее', Number(safe.other) || 0],
|
| 253 |
];
|
|
|
|
| 271 |
}
|
| 272 |
|
| 273 |
|
| 274 |
+
const AUTO_DETECTOR_MODE = 'hf-demo';
|
| 275 |
+
const AUTO_DETECTOR_LABEL = 'src-hf-demo-hybrid-v3';
|
| 276 |
|
| 277 |
|
| 278 |
function AppShell() {
|
|
|
|
| 280 |
const dispatch = useDispatch();
|
| 281 |
const fileInputRef = useRef(null);
|
| 282 |
const [errorText, setErrorText] = useState('');
|
| 283 |
+
const [busyAction, setBusyAction] = useState('');
|
| 284 |
|
| 285 |
const {
|
| 286 |
deleteSelected,
|
|
|
|
| 292 |
() => state.annotations.find((annotation) => annotation.id === state.selectedId) || null,
|
| 293 |
[state.annotations, state.selectedId],
|
| 294 |
);
|
| 295 |
+
const isBusy = Boolean(state.isBusy || busyAction);
|
| 296 |
+
const isAnalyzing = busyAction === 'analyze';
|
| 297 |
+
const isGenerating = busyAction === 'generate';
|
| 298 |
+
const isRunningOcr = busyAction === 'ocr';
|
| 299 |
|
| 300 |
const setStatus = useCallback((text) => {
|
| 301 |
dispatch({ type: A.SET_STATUS, payload: text });
|
|
|
|
| 335 |
dispatch({
|
| 336 |
type: A.SET_PROCESSING,
|
| 337 |
payload: {
|
| 338 |
+
pending: false,
|
| 339 |
ready: false,
|
| 340 |
components: [],
|
| 341 |
counts: {},
|
| 342 |
summary: '',
|
| 343 |
+
detector: '',
|
| 344 |
lastAnalyzedAt: '',
|
| 345 |
},
|
| 346 |
});
|
|
|
|
| 375 |
if (!state.imageDataUrl || !selectedAnnotation) return;
|
| 376 |
|
| 377 |
try {
|
| 378 |
+
setBusyAction('ocr');
|
| 379 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 380 |
setErrorText('');
|
| 381 |
const bounds = annotationBounds(selectedAnnotation);
|
|
|
|
| 409 |
} catch (error) {
|
| 410 |
setErrorText(error.message || 'OCR для выделенного элемента завершился ошибкой.');
|
| 411 |
} finally {
|
| 412 |
+
setBusyAction('');
|
| 413 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 414 |
}
|
| 415 |
}, [dispatch, selectedAnnotation, setStatus, state.imageDataUrl]);
|
|
|
|
| 418 |
if (!state.imageDataUrl) return;
|
| 419 |
|
| 420 |
try {
|
| 421 |
+
setBusyAction('analyze');
|
| 422 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 423 |
setErrorText('');
|
| 424 |
+
dispatch({
|
| 425 |
+
type: A.SET_PROCESSING,
|
| 426 |
+
payload: {
|
| 427 |
+
pending: true,
|
| 428 |
+
ready: false,
|
| 429 |
+
counts: {},
|
| 430 |
+
summary: 'Выполняется анализ схемы...',
|
| 431 |
+
detector: AUTO_DETECTOR_LABEL,
|
| 432 |
+
lastAnalyzedAt: '',
|
| 433 |
+
},
|
| 434 |
+
});
|
| 435 |
+
setStatus('Автораспознавание: выполняется анализ схемы...');
|
| 436 |
const result = await analyzeLayout({
|
| 437 |
imageDataUrl: state.imageDataUrl,
|
| 438 |
config: {
|
| 439 |
detectorMode: AUTO_DETECTOR_MODE,
|
| 440 |
+
sourceName: state.widgetExport.sourceNameHint || state.imageName || undefined,
|
| 441 |
+
titleHint: state.widgetExport.titleHint || state.widgetExport.mnemoTitle || undefined,
|
| 442 |
+
sheetName: state.widgetExport.sheetNameHint || undefined,
|
| 443 |
+
excelPath: state.widgetExport.excelPath || undefined,
|
| 444 |
sensitivity: state.config.sensitivity,
|
| 445 |
imageCorrection: state.config.imageCorrection,
|
| 446 |
enhanceImage: state.config.enhanceImage,
|
|
|
|
| 448 |
},
|
| 449 |
});
|
| 450 |
|
| 451 |
+
console.log('[AutoDetect] Backend response:', {
|
| 452 |
+
engine: result.engine,
|
| 453 |
+
overlaysCount: result.overlays?.length,
|
| 454 |
+
counts: result.counts,
|
| 455 |
+
imageSize: `${result.imageWidth}x${result.imageHeight}`,
|
| 456 |
+
overlayKinds: (result.overlays || []).reduce((acc, o) => {
|
| 457 |
+
acc[o.kind] = (acc[o.kind] || 0) + 1;
|
| 458 |
+
return acc;
|
| 459 |
+
}, {}),
|
| 460 |
+
});
|
| 461 |
const manualAnnotations = state.annotations.filter((annotation) => annotation.source !== 'auto');
|
| 462 |
const created = buildAutoAnnotationsFromDetectionItems(result.overlays, manualAnnotations);
|
| 463 |
+
console.log('[AutoDetect] Created annotations:', created.length, 'from', result.overlays?.length, 'overlays');
|
| 464 |
dispatch({
|
| 465 |
type: A.SET_PROCESSING,
|
| 466 |
payload: {
|
| 467 |
+
pending: false,
|
| 468 |
ready: true,
|
| 469 |
width: Number(result.imageWidth) || state.imageWidth,
|
| 470 |
height: Number(result.imageHeight) || state.imageHeight,
|
|
|
|
| 472 |
components: Array.isArray(result.overlays) ? result.overlays : [],
|
| 473 |
counts: result.counts || {},
|
| 474 |
summary: result.summary || '',
|
| 475 |
+
detector: result.engine || 'src-hf-demo-v1',
|
| 476 |
lastAnalyzedAt: new Date().toISOString(),
|
| 477 |
},
|
| 478 |
});
|
|
|
|
| 491 |
dispatch({ type: A.SELECT_ANNOTATION, payload: created[0].id });
|
| 492 |
setStatus(`${result.summary || 'Автораспознавание завершено.'} Создано автоаннотаций: ${created.length}.`);
|
| 493 |
} catch (error) {
|
| 494 |
+
dispatch({
|
| 495 |
+
type: A.SET_PROCESSING,
|
| 496 |
+
payload: {
|
| 497 |
+
pending: false,
|
| 498 |
+
ready: false,
|
| 499 |
+
summary: '',
|
| 500 |
+
detector: '',
|
| 501 |
+
},
|
| 502 |
+
});
|
| 503 |
setErrorText(error.message || 'Автораспознавание завершилось ошибкой.');
|
| 504 |
} finally {
|
| 505 |
+
setBusyAction('');
|
| 506 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 507 |
}
|
| 508 |
}, [dispatch, setStatus, setWidgetExport, state.annotations, state.config.enhanceImage, state.config.ignoreLines, state.config.imageCorrection, state.config.sensitivity, state.imageDataUrl, state.imageHeight, state.imageWidth]);
|
|
|
|
| 514 |
dispatch({
|
| 515 |
type: A.SET_PROCESSING,
|
| 516 |
payload: {
|
| 517 |
+
pending: false,
|
| 518 |
ready: false,
|
| 519 |
components: [],
|
| 520 |
counts: {},
|
| 521 |
summary: '',
|
| 522 |
+
detector: '',
|
| 523 |
lastAnalyzedAt: '',
|
| 524 |
},
|
| 525 |
});
|
|
|
|
| 536 |
dispatch({
|
| 537 |
type: A.SET_PROCESSING,
|
| 538 |
payload: {
|
| 539 |
+
pending: false,
|
| 540 |
ready: false,
|
| 541 |
components: [],
|
| 542 |
counts: {},
|
| 543 |
summary: '',
|
| 544 |
+
detector: '',
|
| 545 |
lastAnalyzedAt: '',
|
| 546 |
},
|
| 547 |
});
|
| 548 |
setStatus('Автоматические аннотации удалены.');
|
| 549 |
}, [dispatch, setStatus, state.annotations, state.processing]);
|
| 550 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
const handleGenerateImport = useCallback(async () => {
|
| 552 |
if (!state.imageDataUrl || !state.annotations.length) {
|
| 553 |
setErrorText('Сначала загрузите изображение и создайте или проверьте аннотации элементов схемы.');
|
|
|
|
| 555 |
}
|
| 556 |
|
| 557 |
try {
|
| 558 |
+
setBusyAction('generate');
|
| 559 |
dispatch({ type: A.SET_BUSY, payload: true });
|
| 560 |
setErrorText('');
|
| 561 |
setStatus('Генерация import XML...');
|
|
|
|
| 570 |
excelPath: state.widgetExport.excelPath || undefined,
|
| 571 |
});
|
| 572 |
|
| 573 |
+
const nextAnnotations = mergeImportResultsIntoAnnotations(
|
| 574 |
+
state.annotations,
|
| 575 |
+
result.bindings,
|
| 576 |
+
result.annotationResults,
|
| 577 |
+
);
|
| 578 |
+
dispatch({ type: A.SET_ANNOTATIONS, payload: nextAnnotations });
|
| 579 |
setWidgetExport({
|
| 580 |
generatedXmlText: result.xmlText,
|
| 581 |
mnemoTitle: result.title || state.widgetExport.mnemoTitle,
|
|
|
|
| 586 |
exportedCount: result.exportedCount,
|
| 587 |
unmatchedNumbers: result.unmatchedNumbers || [],
|
| 588 |
missingVisuals: result.missingVisuals || [],
|
| 589 |
+
annotationResults: result.annotationResults || [],
|
| 590 |
lastGeneratedAt: new Date().toISOString(),
|
| 591 |
});
|
| 592 |
setStatus(
|
|
|
|
| 595 |
} catch (error) {
|
| 596 |
setErrorText(error.message || 'Не удалось сформировать import XML.');
|
| 597 |
} finally {
|
| 598 |
+
setBusyAction('');
|
| 599 |
dispatch({ type: A.SET_BUSY, payload: false });
|
| 600 |
}
|
| 601 |
+
}, [dispatch, setStatus, setWidgetExport, state.annotations, state.imageDataUrl, state.imageName, state.widgetExport]);
|
| 602 |
|
| 603 |
const handleDownloadXml = useCallback(() => {
|
| 604 |
const xmlText = String(state.widgetExport.generatedXmlText || '').trim();
|
|
|
|
| 610 |
downloadText(xmlText, defaultName, 'application/xml;charset=utf-8');
|
| 611 |
}, [state.imageName, state.widgetExport.generatedXmlText, state.widgetExport.sheetResolvedName]);
|
| 612 |
|
| 613 |
+
const handlePlaceElement = useCallback((item, section) => {
|
| 614 |
+
if (!state.imageDataUrl) return;
|
| 615 |
+
const cx = state.imageWidth / 2;
|
| 616 |
+
const cy = state.imageHeight / 2;
|
| 617 |
+
const w = Number(item.width) || 80;
|
| 618 |
+
const h = Number(item.height) || 40;
|
| 619 |
+
const x = Math.max(0, cx - w / 2);
|
| 620 |
+
const y = Math.max(0, cy - h / 2);
|
| 621 |
+
const points = [
|
| 622 |
+
{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h },
|
| 623 |
+
];
|
| 624 |
+
const basicShape = section === 'basics' ? String(item.name || '').toLowerCase() : '';
|
| 625 |
+
const number = nextAnnotationNumber(state.annotations);
|
| 626 |
+
|
| 627 |
+
const annotation = {
|
| 628 |
+
id: uid('ann'),
|
| 629 |
+
number,
|
| 630 |
+
displayNumber: null,
|
| 631 |
+
bindingUid: '',
|
| 632 |
+
detectedKind: section === 'statics' ? 'shape' : section === 'widgets' ? 'widget' : 'other',
|
| 633 |
+
type: 'rect',
|
| 634 |
+
points,
|
| 635 |
+
source: 'manual',
|
| 636 |
+
confidence: 1.0,
|
| 637 |
+
note: item.displayName || item.label || item.name || '',
|
| 638 |
+
contextPath: '',
|
| 639 |
+
allowDuplicate: false,
|
| 640 |
+
category: section === 'statics' ? 'static' : section === 'widgets' ? 'widget' : 'other',
|
| 641 |
+
widgetNameOverride: section === 'widgets' ? item.name : '',
|
| 642 |
+
staticShapeNameOverride: section === 'statics' ? item.name : '',
|
| 643 |
+
basicShape,
|
| 644 |
+
svgPath: section === 'statics' ? String(item.svgPath || '') : '',
|
| 645 |
+
svgWidth: section === 'statics' ? (Number(item.width) || w) : w,
|
| 646 |
+
svgHeight: section === 'statics' ? (Number(item.height) || h) : h,
|
| 647 |
+
rotation: 0,
|
| 648 |
+
createdAt: Date.now(),
|
| 649 |
+
reviewed: true,
|
| 650 |
+
reviewedAt: Date.now(),
|
| 651 |
+
};
|
| 652 |
+
|
| 653 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 654 |
+
dispatch({ type: A.ADD_ANNOTATION, payload: annotation });
|
| 655 |
+
setStatus(`Добавлен элемент: ${item.displayName || item.name}`);
|
| 656 |
+
}, [dispatch, setStatus, state.annotations, state.imageDataUrl, state.imageWidth, state.imageHeight]);
|
| 657 |
+
|
| 658 |
useKeyboard({
|
| 659 |
onUndo: () => dispatch({ type: A.UNDO }),
|
| 660 |
onRedo: () => dispatch({ type: A.REDO }),
|
|
|
|
| 711 |
</button>
|
| 712 |
{hasImage && (
|
| 713 |
<>
|
| 714 |
+
<button className="btn btn-warn" onClick={handleAutoDetect} disabled={isBusy}>
|
| 715 |
+
{isAnalyzing ? <><span className="spinner" /> Анализ...</> : 'Автораспознавание'}
|
| 716 |
</button>
|
| 717 |
+
<button className="btn btn-ghost" onClick={handleSelectedOcr} disabled={!selectedAnnotation || isBusy}>
|
| 718 |
+
{isRunningOcr ? <><span className="spinner" /> OCR...</> : 'OCR выделенного'}
|
| 719 |
</button>
|
| 720 |
+
<button className="btn btn-primary" onClick={handleGenerateImport} disabled={!state.annotations.length || isBusy}>
|
| 721 |
+
{isGenerating ? <><span className="spinner" /> Генерация...</> : 'Сформировать XML'}
|
| 722 |
</button>
|
| 723 |
<button className="btn btn-success" onClick={handleDownloadXml} disabled={!hasGeneratedXml}>
|
| 724 |
Скачать XML
|
| 725 |
</button>
|
| 726 |
+
<button className="btn btn-ghost" onClick={handleReset} disabled={isBusy}>
|
| 727 |
Сбросить
|
| 728 |
</button>
|
| 729 |
</>
|
|
|
|
| 736 |
<ImageUpload onImageLoad={handleImageLoad} />
|
| 737 |
<div className="empty-hints">
|
| 738 |
<h3>Что умеет новая реализация</h3>
|
| 739 |
+
<p>Кнопка `Автораспознавание` запускает тот же локальный детектор, что использует оригинальный `MNEMO OCR — HF Demo`, через `src.pipeline_hf.process_single_image`.</p>
|
| 740 |
+
<p>Распознанные элементы попадают в аннотации нового фронта и затем выгружаются в import XML. То, что детектор не нашёл, можно дорисовать вручную и выгрузить тем же путём.</p>
|
| 741 |
<p>Файл Приложения сервер найдёт автоматически в проекте. При необходимости путь можно переопределить после загрузки изображения.</p>
|
| 742 |
</div>
|
| 743 |
</div>
|
| 744 |
) : (
|
| 745 |
<div className="main-content editor-layout">
|
| 746 |
+
<ElementLibraryPanel onPlaceElement={handlePlaceElement} />
|
| 747 |
<section className="workspace-stack">
|
| 748 |
<Toolbar
|
| 749 |
onUndo={() => dispatch({ type: A.UNDO })}
|
|
|
|
| 761 |
<span className="panel-note">
|
| 762 |
{state.processing.lastAnalyzedAt
|
| 763 |
? new Date(state.processing.lastAnalyzedAt).toLocaleString()
|
| 764 |
+
: state.processing.pending ? 'выполняется анализ' : 'ещё не запускалось'}
|
| 765 |
</span>
|
| 766 |
</div>
|
| 767 |
|
|
|
|
| 772 |
</div>
|
| 773 |
<div className="summary-item">
|
| 774 |
<span>Сводка</span>
|
| 775 |
+
<strong>
|
| 776 |
+
{state.processing.pending
|
| 777 |
+
? 'выполняется анализ'
|
| 778 |
+
: state.processing.ready
|
| 779 |
+
? formatDetectionCounts(state.processing.counts)
|
| 780 |
+
: 'ожидание анализа'}
|
| 781 |
+
</strong>
|
| 782 |
</div>
|
| 783 |
</div>
|
| 784 |
|
|
|
|
| 843 |
</div>
|
| 844 |
|
| 845 |
<div className="panel-actions">
|
| 846 |
+
<button className="btn btn-primary" onClick={handleGenerateImport} disabled={!state.annotations.length || isBusy}>
|
| 847 |
+
{isGenerating ? <><span className="spinner" /> ...</> : 'Сформировать XML'}
|
| 848 |
</button>
|
| 849 |
<button className="btn btn-success" onClick={handleDownloadXml} disabled={!hasGeneratedXml}>
|
| 850 |
Скачать
|
|
|
|
| 889 |
)}
|
| 890 |
</section>
|
| 891 |
|
| 892 |
+
{/* XML Preview removed — use Скачать XML button */}
|
| 893 |
|
| 894 |
+
<Inspector onOcrSelected={handleSelectedOcr} onDelete={deleteSelected} />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 895 |
</aside>
|
| 896 |
</div>
|
| 897 |
)}
|
web-new/src/api.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
| 1 |
const API_BASE = '/.mnemo-studio-api';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
export async function checkHealth() {
|
| 4 |
const res = await fetch(`${API_BASE}/health`, { cache: 'no-store' });
|
|
@@ -20,12 +39,15 @@ export async function runOcr({ imageDataUrl, region = null, lang = 'rus+eng' })
|
|
| 20 |
|
| 21 |
let res;
|
| 22 |
try {
|
| 23 |
-
res = await
|
| 24 |
method: 'POST',
|
| 25 |
headers: { 'Content-Type': 'application/json' },
|
| 26 |
body: JSON.stringify(body),
|
| 27 |
-
});
|
| 28 |
} catch (networkError) {
|
|
|
|
|
|
|
|
|
|
| 29 |
throw new Error('Сервер недоступен. Запустите бэкенд: python app.py');
|
| 30 |
}
|
| 31 |
|
|
@@ -55,12 +77,15 @@ export async function saveDatasetSample(payload) {
|
|
| 55 |
export async function analyzeLayout(payload) {
|
| 56 |
let res;
|
| 57 |
try {
|
| 58 |
-
res = await
|
| 59 |
method: 'POST',
|
| 60 |
headers: { 'Content-Type': 'application/json' },
|
| 61 |
body: JSON.stringify(payload),
|
| 62 |
-
});
|
| 63 |
} catch (networkError) {
|
|
|
|
|
|
|
|
|
|
| 64 |
throw new Error(
|
| 65 |
'Не удалось подключиться к серверу. Убедитесь, что бэкенд запущен (python app.py) и доступен на порту 7860.'
|
| 66 |
);
|
|
@@ -74,15 +99,26 @@ export async function analyzeLayout(payload) {
|
|
| 74 |
return res.json();
|
| 75 |
}
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
export async function generateImportXml(payload) {
|
| 78 |
let res;
|
| 79 |
try {
|
| 80 |
-
res = await
|
| 81 |
method: 'POST',
|
| 82 |
headers: { 'Content-Type': 'application/json' },
|
| 83 |
body: JSON.stringify(payload),
|
| 84 |
-
});
|
| 85 |
} catch (networkError) {
|
|
|
|
|
|
|
|
|
|
| 86 |
throw new Error('Сервер недоступен. Запустите бэкенд: python app.py');
|
| 87 |
}
|
| 88 |
|
|
|
|
| 1 |
const API_BASE = '/.mnemo-studio-api';
|
| 2 |
+
const ANALYZE_TIMEOUT_MS = 0;
|
| 3 |
+
const OCR_TIMEOUT_MS = 30000;
|
| 4 |
+
const XML_TIMEOUT_MS = 60000;
|
| 5 |
+
|
| 6 |
+
async function fetchWithTimeout(url, options = {}, timeoutMs = 30000) {
|
| 7 |
+
if (!timeoutMs || timeoutMs <= 0) {
|
| 8 |
+
return fetch(url, options);
|
| 9 |
+
}
|
| 10 |
+
const controller = new AbortController();
|
| 11 |
+
const timeoutId = window.setTimeout(() => controller.abort(), timeoutMs);
|
| 12 |
+
try {
|
| 13 |
+
return await fetch(url, {
|
| 14 |
+
...options,
|
| 15 |
+
signal: controller.signal,
|
| 16 |
+
});
|
| 17 |
+
} finally {
|
| 18 |
+
window.clearTimeout(timeoutId);
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
|
| 22 |
export async function checkHealth() {
|
| 23 |
const res = await fetch(`${API_BASE}/health`, { cache: 'no-store' });
|
|
|
|
| 39 |
|
| 40 |
let res;
|
| 41 |
try {
|
| 42 |
+
res = await fetchWithTimeout(`${API_BASE}/ocr`, {
|
| 43 |
method: 'POST',
|
| 44 |
headers: { 'Content-Type': 'application/json' },
|
| 45 |
body: JSON.stringify(body),
|
| 46 |
+
}, OCR_TIMEOUT_MS);
|
| 47 |
} catch (networkError) {
|
| 48 |
+
if (networkError?.name === 'AbortError') {
|
| 49 |
+
throw new Error('OCR превысил лимит ожидания. Попробуйте меньшую область.');
|
| 50 |
+
}
|
| 51 |
throw new Error('Сервер недоступен. Запустите бэкенд: python app.py');
|
| 52 |
}
|
| 53 |
|
|
|
|
| 77 |
export async function analyzeLayout(payload) {
|
| 78 |
let res;
|
| 79 |
try {
|
| 80 |
+
res = await fetchWithTimeout(`${API_BASE}/analyze-layout`, {
|
| 81 |
method: 'POST',
|
| 82 |
headers: { 'Content-Type': 'application/json' },
|
| 83 |
body: JSON.stringify(payload),
|
| 84 |
+
}, ANALYZE_TIMEOUT_MS);
|
| 85 |
} catch (networkError) {
|
| 86 |
+
if (networkError?.name === 'AbortError') {
|
| 87 |
+
throw new Error('Анализ выполняется дольше обычного. Проверьте логи backend и дождитесь завершения обработки.');
|
| 88 |
+
}
|
| 89 |
throw new Error(
|
| 90 |
'Не удалось подключиться к серверу. Убедитесь, что бэкенд запущен (python app.py) и доступен на порту 7860.'
|
| 91 |
);
|
|
|
|
| 99 |
return res.json();
|
| 100 |
}
|
| 101 |
|
| 102 |
+
export async function fetchElementLibrary() {
|
| 103 |
+
const res = await fetch(`${API_BASE}/element-library`, { cache: 'no-store' });
|
| 104 |
+
if (!res.ok) {
|
| 105 |
+
throw new Error(`Element library failed: ${res.status}`);
|
| 106 |
+
}
|
| 107 |
+
return res.json();
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
export async function generateImportXml(payload) {
|
| 111 |
let res;
|
| 112 |
try {
|
| 113 |
+
res = await fetchWithTimeout(`${API_BASE}/generate-import-xml`, {
|
| 114 |
method: 'POST',
|
| 115 |
headers: { 'Content-Type': 'application/json' },
|
| 116 |
body: JSON.stringify(payload),
|
| 117 |
+
}, XML_TIMEOUT_MS);
|
| 118 |
} catch (networkError) {
|
| 119 |
+
if (networkError?.name === 'AbortError') {
|
| 120 |
+
throw new Error('Генерация XML превысила лимит ожидания.');
|
| 121 |
+
}
|
| 122 |
throw new Error('Сервер недоступен. Запустите бэкенд: python app.py');
|
| 123 |
}
|
| 124 |
|
web-new/src/components/ElementLibraryPanel.css
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.element-library-panel {
|
| 2 |
+
display: flex;
|
| 3 |
+
flex-direction: column;
|
| 4 |
+
background: var(--surface);
|
| 5 |
+
border-right: 1px solid var(--border);
|
| 6 |
+
overflow: hidden;
|
| 7 |
+
min-width: 0;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
.lib-header {
|
| 11 |
+
padding: 8px 10px 6px;
|
| 12 |
+
font-size: 12px;
|
| 13 |
+
font-weight: 600;
|
| 14 |
+
color: var(--text);
|
| 15 |
+
border-bottom: 1px solid var(--border);
|
| 16 |
+
flex-shrink: 0;
|
| 17 |
+
white-space: nowrap;
|
| 18 |
+
overflow: hidden;
|
| 19 |
+
text-overflow: ellipsis;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
.lib-search {
|
| 23 |
+
padding: 5px 6px;
|
| 24 |
+
flex-shrink: 0;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.lib-search input {
|
| 28 |
+
width: 100%;
|
| 29 |
+
box-sizing: border-box;
|
| 30 |
+
padding: 4px 6px;
|
| 31 |
+
font-size: 11px;
|
| 32 |
+
border: 1px solid var(--border);
|
| 33 |
+
border-radius: 4px;
|
| 34 |
+
background: var(--surface-alt, #1e293b);
|
| 35 |
+
color: var(--text);
|
| 36 |
+
outline: none;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
.lib-search input:focus {
|
| 40 |
+
border-color: var(--accent);
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
.lib-sections-scroll {
|
| 44 |
+
flex: 1;
|
| 45 |
+
overflow-y: auto;
|
| 46 |
+
overflow-x: hidden;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
.lib-section {
|
| 50 |
+
border-bottom: 1px solid var(--border);
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
.lib-section-header {
|
| 54 |
+
display: flex;
|
| 55 |
+
align-items: center;
|
| 56 |
+
gap: 4px;
|
| 57 |
+
width: 100%;
|
| 58 |
+
padding: 5px 8px;
|
| 59 |
+
font-size: 10px;
|
| 60 |
+
font-weight: 600;
|
| 61 |
+
color: var(--text-muted);
|
| 62 |
+
background: transparent;
|
| 63 |
+
border: none;
|
| 64 |
+
cursor: pointer;
|
| 65 |
+
text-align: left;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
.lib-section-header:hover {
|
| 69 |
+
background: var(--surface-hover, rgba(255,255,255,0.04));
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.lib-section-arrow {
|
| 73 |
+
font-size: 9px;
|
| 74 |
+
width: 10px;
|
| 75 |
+
flex-shrink: 0;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.lib-section-title {
|
| 79 |
+
flex: 1;
|
| 80 |
+
overflow: hidden;
|
| 81 |
+
text-overflow: ellipsis;
|
| 82 |
+
white-space: nowrap;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
.lib-section-count {
|
| 86 |
+
font-size: 9px;
|
| 87 |
+
color: var(--text-muted);
|
| 88 |
+
opacity: 0.6;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.lib-section-body {
|
| 92 |
+
padding: 2px 4px 6px;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
.lib-grid {
|
| 96 |
+
display: grid;
|
| 97 |
+
grid-template-columns: repeat(2, 1fr);
|
| 98 |
+
gap: 2px;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.lib-item {
|
| 102 |
+
display: flex;
|
| 103 |
+
flex-direction: column;
|
| 104 |
+
align-items: center;
|
| 105 |
+
gap: 2px;
|
| 106 |
+
padding: 4px 2px;
|
| 107 |
+
background: transparent;
|
| 108 |
+
border: 1px solid transparent;
|
| 109 |
+
border-radius: 3px;
|
| 110 |
+
cursor: pointer;
|
| 111 |
+
color: var(--text);
|
| 112 |
+
transition: background 0.12s, border-color 0.12s;
|
| 113 |
+
overflow: hidden;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.lib-item:hover {
|
| 117 |
+
background: var(--surface-hover, rgba(255,255,255,0.06));
|
| 118 |
+
border-color: var(--border);
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
.lib-item:active {
|
| 122 |
+
background: rgba(255,255,255,0.1);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.lib-icon {
|
| 126 |
+
width: 30px;
|
| 127 |
+
height: 30px;
|
| 128 |
+
display: flex;
|
| 129 |
+
align-items: center;
|
| 130 |
+
justify-content: center;
|
| 131 |
+
flex-shrink: 0;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
.lib-icon svg,
|
| 135 |
+
.lib-icon .lib-thumb {
|
| 136 |
+
width: 100%;
|
| 137 |
+
height: 100%;
|
| 138 |
+
color: var(--text-muted);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
.lib-name {
|
| 142 |
+
font-size: 8px;
|
| 143 |
+
line-height: 1.1;
|
| 144 |
+
text-align: center;
|
| 145 |
+
color: var(--text-muted);
|
| 146 |
+
overflow: hidden;
|
| 147 |
+
text-overflow: ellipsis;
|
| 148 |
+
white-space: nowrap;
|
| 149 |
+
max-width: 100%;
|
| 150 |
+
width: 100%;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
.lib-loading,
|
| 154 |
+
.lib-error {
|
| 155 |
+
padding: 16px 10px;
|
| 156 |
+
font-size: 11px;
|
| 157 |
+
color: var(--text-muted);
|
| 158 |
+
text-align: center;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
.lib-error {
|
| 162 |
+
color: var(--danger);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
@media (max-width: 1200px) {
|
| 166 |
+
.element-library-panel {
|
| 167 |
+
display: none;
|
| 168 |
+
}
|
| 169 |
+
}
|
web-new/src/components/ElementLibraryPanel.jsx
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
| 2 |
+
import { fetchElementLibrary } from '../api';
|
| 3 |
+
import * as A from '../store/actions';
|
| 4 |
+
import { useDispatch, useStore } from '../store/context';
|
| 5 |
+
import './ElementLibraryPanel.css';
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
const SECTION_ORDER = ['basics', 'statics', 'widgets'];
|
| 9 |
+
const SECTION_LABELS = {
|
| 10 |
+
basics: 'Базовые фигуры',
|
| 11 |
+
statics: 'Статические шейпы',
|
| 12 |
+
widgets: 'Динамические виджеты',
|
| 13 |
+
};
|
| 14 |
+
|
| 15 |
+
const BASIC_ICONS = {
|
| 16 |
+
rectangle: (
|
| 17 |
+
<svg viewBox="0 0 32 24"><rect x="2" y="2" width="28" height="20" fill="none" stroke="currentColor" strokeWidth="1.5" /></svg>
|
| 18 |
+
),
|
| 19 |
+
text: (
|
| 20 |
+
<svg viewBox="0 0 32 24"><text x="16" y="17" textAnchor="middle" fontSize="14" fill="currentColor">T</text></svg>
|
| 21 |
+
),
|
| 22 |
+
line: (
|
| 23 |
+
<svg viewBox="0 0 32 24"><line x1="4" y1="20" x2="28" y2="4" stroke="currentColor" strokeWidth="1.5" /></svg>
|
| 24 |
+
),
|
| 25 |
+
arrow: (
|
| 26 |
+
<svg viewBox="0 0 32 24"><line x1="4" y1="12" x2="24" y2="12" stroke="currentColor" strokeWidth="1.5" /><path d="M 22 8 L 28 12 L 22 16" fill="none" stroke="currentColor" strokeWidth="1.5" /></svg>
|
| 27 |
+
),
|
| 28 |
+
ellipse: (
|
| 29 |
+
<svg viewBox="0 0 32 24"><ellipse cx="16" cy="12" rx="13" ry="9" fill="none" stroke="currentColor" strokeWidth="1.5" /></svg>
|
| 30 |
+
),
|
| 31 |
+
table: (
|
| 32 |
+
<svg viewBox="0 0 32 24"><rect x="2" y="2" width="28" height="20" fill="none" stroke="currentColor" strokeWidth="1.5" /><line x1="2" y1="9" x2="30" y2="9" stroke="currentColor" strokeWidth="1" /><line x1="16" y1="9" x2="16" y2="22" stroke="currentColor" strokeWidth="1" /></svg>
|
| 33 |
+
),
|
| 34 |
+
};
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
function StaticShapeThumbnail({ svgPath, width, height }) {
|
| 38 |
+
if (!svgPath) {
|
| 39 |
+
return (
|
| 40 |
+
<svg viewBox="0 0 32 32" className="lib-thumb">
|
| 41 |
+
<rect x="4" y="4" width="24" height="24" fill="none" stroke="currentColor" strokeWidth="1" strokeDasharray="3 2" />
|
| 42 |
+
</svg>
|
| 43 |
+
);
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
const vw = width || 32;
|
| 47 |
+
const vh = height || 32;
|
| 48 |
+
const pad = 2;
|
| 49 |
+
|
| 50 |
+
return (
|
| 51 |
+
<svg viewBox={`${-pad} ${-pad} ${vw + pad * 2} ${vh + pad * 2}`} className="lib-thumb">
|
| 52 |
+
<path d={svgPath} fill="none" stroke="currentColor" strokeWidth={Math.max(0.8, vw / 32)} />
|
| 53 |
+
</svg>
|
| 54 |
+
);
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
const LibraryItem = memo(function LibraryItem({ item, section, onClick }) {
|
| 59 |
+
const handleClick = useCallback(() => {
|
| 60 |
+
onClick(item, section);
|
| 61 |
+
}, [item, section, onClick]);
|
| 62 |
+
|
| 63 |
+
if (section === 'basics') {
|
| 64 |
+
return (
|
| 65 |
+
<button className="lib-item" onClick={handleClick} title={item.label}>
|
| 66 |
+
<div className="lib-icon">{BASIC_ICONS[item.icon] || BASIC_ICONS.rectangle}</div>
|
| 67 |
+
<span className="lib-name">{item.label}</span>
|
| 68 |
+
</button>
|
| 69 |
+
);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
if (section === 'statics') {
|
| 73 |
+
return (
|
| 74 |
+
<button className="lib-item" onClick={handleClick} title={item.displayName}>
|
| 75 |
+
<div className="lib-icon">
|
| 76 |
+
<StaticShapeThumbnail svgPath={item.svgPath} width={item.width} height={item.height} />
|
| 77 |
+
</div>
|
| 78 |
+
<span className="lib-name">{item.displayName}</span>
|
| 79 |
+
</button>
|
| 80 |
+
);
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
const catColor = {
|
| 84 |
+
equipment: '#f97316',
|
| 85 |
+
valve: '#8b5cf6',
|
| 86 |
+
indicator: '#22c55e',
|
| 87 |
+
value: '#eab308',
|
| 88 |
+
table: '#60a5fa',
|
| 89 |
+
static: '#94a3b8',
|
| 90 |
+
arrow: '#ff4f87',
|
| 91 |
+
other: '#6b7280',
|
| 92 |
+
}[item.category] || '#6b7280';
|
| 93 |
+
|
| 94 |
+
return (
|
| 95 |
+
<button className="lib-item" onClick={handleClick} title={item.displayName}>
|
| 96 |
+
<div className="lib-icon">
|
| 97 |
+
<svg viewBox="0 0 32 32" className="lib-thumb">
|
| 98 |
+
<rect x="2" y="2" width="28" height="28" rx="3" fill={catColor} opacity="0.15" stroke={catColor} strokeWidth="1" />
|
| 99 |
+
<text x="16" y="18" textAnchor="middle" fontSize="8" fill={catColor} fontWeight="bold">W</text>
|
| 100 |
+
</svg>
|
| 101 |
+
</div>
|
| 102 |
+
<span className="lib-name">{item.displayName}</span>
|
| 103 |
+
</button>
|
| 104 |
+
);
|
| 105 |
+
});
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
function CollapsibleSection({ title, count, defaultOpen, children }) {
|
| 109 |
+
const [open, setOpen] = useState(defaultOpen ?? true);
|
| 110 |
+
|
| 111 |
+
return (
|
| 112 |
+
<div className={`lib-section ${open ? 'open' : 'closed'}`}>
|
| 113 |
+
<button className="lib-section-header" onClick={() => setOpen((v) => !v)}>
|
| 114 |
+
<span className="lib-section-arrow">{open ? '▾' : '▸'}</span>
|
| 115 |
+
<span className="lib-section-title">{title}</span>
|
| 116 |
+
<span className="lib-section-count">{count}</span>
|
| 117 |
+
</button>
|
| 118 |
+
{open && <div className="lib-section-body">{children}</div>}
|
| 119 |
+
</div>
|
| 120 |
+
);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
export default function ElementLibraryPanel({ onPlaceElement }) {
|
| 125 |
+
const state = useStore();
|
| 126 |
+
const dispatch = useDispatch();
|
| 127 |
+
const [search, setSearch] = useState('');
|
| 128 |
+
const [error, setError] = useState('');
|
| 129 |
+
|
| 130 |
+
useEffect(() => {
|
| 131 |
+
if (state.elementLibrary.loaded) return;
|
| 132 |
+
let cancelled = false;
|
| 133 |
+
fetchElementLibrary()
|
| 134 |
+
.then((data) => {
|
| 135 |
+
if (!cancelled) {
|
| 136 |
+
dispatch({ type: A.SET_ELEMENT_LIBRARY, payload: data });
|
| 137 |
+
}
|
| 138 |
+
})
|
| 139 |
+
.catch((err) => {
|
| 140 |
+
if (!cancelled) setError(err.message);
|
| 141 |
+
});
|
| 142 |
+
return () => { cancelled = true; };
|
| 143 |
+
}, [state.elementLibrary.loaded, dispatch]);
|
| 144 |
+
|
| 145 |
+
const filtered = useMemo(() => {
|
| 146 |
+
const q = search.trim().toLowerCase();
|
| 147 |
+
const lib = state.elementLibrary;
|
| 148 |
+
if (!q) return lib;
|
| 149 |
+
return {
|
| 150 |
+
basics: lib.basics.filter((i) => (i.label || i.name).toLowerCase().includes(q)),
|
| 151 |
+
statics: lib.statics.filter((i) => (i.displayName || i.name).toLowerCase().includes(q)),
|
| 152 |
+
widgets: lib.widgets.filter((i) => (i.displayName || i.name).toLowerCase().includes(q)),
|
| 153 |
+
};
|
| 154 |
+
}, [search, state.elementLibrary]);
|
| 155 |
+
|
| 156 |
+
const handleClick = useCallback((item, section) => {
|
| 157 |
+
if (onPlaceElement) onPlaceElement(item, section);
|
| 158 |
+
}, [onPlaceElement]);
|
| 159 |
+
|
| 160 |
+
if (error) {
|
| 161 |
+
return (
|
| 162 |
+
<aside className="element-library-panel">
|
| 163 |
+
<div className="lib-header">Библиотека</div>
|
| 164 |
+
<div className="lib-error">{error}</div>
|
| 165 |
+
</aside>
|
| 166 |
+
);
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
if (!state.elementLibrary.loaded) {
|
| 170 |
+
return (
|
| 171 |
+
<aside className="element-library-panel">
|
| 172 |
+
<div className="lib-header">Библиотека</div>
|
| 173 |
+
<div className="lib-loading"><span className="spinner" /> Загрузка...</div>
|
| 174 |
+
</aside>
|
| 175 |
+
);
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
return (
|
| 179 |
+
<aside className="element-library-panel">
|
| 180 |
+
<div className="lib-header">Библиотека</div>
|
| 181 |
+
<div className="lib-search">
|
| 182 |
+
<input
|
| 183 |
+
type="text"
|
| 184 |
+
placeholder="Поиск..."
|
| 185 |
+
value={search}
|
| 186 |
+
onChange={(e) => setSearch(e.target.value)}
|
| 187 |
+
/>
|
| 188 |
+
</div>
|
| 189 |
+
|
| 190 |
+
<div className="lib-sections-scroll">
|
| 191 |
+
{SECTION_ORDER.map((section) => {
|
| 192 |
+
const items = filtered[section] || [];
|
| 193 |
+
if (!items.length && search) return null;
|
| 194 |
+
return (
|
| 195 |
+
<CollapsibleSection
|
| 196 |
+
key={section}
|
| 197 |
+
title={SECTION_LABELS[section]}
|
| 198 |
+
count={items.length}
|
| 199 |
+
defaultOpen={section === 'basics'}
|
| 200 |
+
>
|
| 201 |
+
<div className="lib-grid">
|
| 202 |
+
{items.map((item) => (
|
| 203 |
+
<LibraryItem
|
| 204 |
+
key={item.name}
|
| 205 |
+
item={item}
|
| 206 |
+
section={section}
|
| 207 |
+
onClick={handleClick}
|
| 208 |
+
/>
|
| 209 |
+
))}
|
| 210 |
+
</div>
|
| 211 |
+
</CollapsibleSection>
|
| 212 |
+
);
|
| 213 |
+
})}
|
| 214 |
+
</div>
|
| 215 |
+
</aside>
|
| 216 |
+
);
|
| 217 |
+
}
|
web-new/src/components/Inspector.jsx
CHANGED
|
@@ -1,9 +1,72 @@
|
|
| 1 |
import { useCallback } from 'react';
|
| 2 |
import { useStore, useDispatch } from '../store/context';
|
| 3 |
import * as A from '../store/actions';
|
| 4 |
-
import {
|
| 5 |
import { boundsOfPoints, polygonArea, round } from '../utils/geometry';
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
export default function Inspector({ onOcrSelected, onDelete }) {
|
| 8 |
const state = useStore();
|
| 9 |
const dispatch = useDispatch();
|
|
@@ -19,11 +82,28 @@ export default function Inspector({ onOcrSelected, onDelete }) {
|
|
| 19 |
});
|
| 20 |
}, [dispatch, selectedId]);
|
| 21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
const filtered = annotations.filter((a) => {
|
| 23 |
if (!filterText) return true;
|
| 24 |
const q = filterText.toLowerCase();
|
| 25 |
return (
|
| 26 |
String(a.number).includes(q)
|
|
|
|
| 27 |
|| (a.bindingUid || '').includes(q)
|
| 28 |
|| (a.note || '').toLowerCase().includes(q)
|
| 29 |
|| (a.category || '').toLowerCase().includes(q)
|
|
@@ -47,12 +127,17 @@ export default function Inspector({ onOcrSelected, onDelete }) {
|
|
| 47 |
{selectedAnn ? (
|
| 48 |
<div className="inspector-editor">
|
| 49 |
<div className="inspector-badges">
|
| 50 |
-
<span className="badge" style={{ background: `${
|
| 51 |
-
{
|
| 52 |
</span>
|
| 53 |
-
<span className="inspector-meta">
|
| 54 |
{selectedAnn.detectedKind && <span className="inspector-meta">{selectedAnn.detectedKind}</span>}
|
| 55 |
{selectedAnn.bindingUid && <span className="inspector-meta uid">UID {selectedAnn.bindingUid}</span>}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
</div>
|
| 57 |
|
| 58 |
<div className="panel-grid">
|
|
@@ -81,11 +166,11 @@ export default function Inspector({ onOcrSelected, onDelete }) {
|
|
| 81 |
<label className="field">
|
| 82 |
<span>Категория</span>
|
| 83 |
<select
|
| 84 |
-
value={selectedAnn
|
| 85 |
-
onChange={(e) =>
|
| 86 |
>
|
| 87 |
-
{
|
| 88 |
-
<option key={
|
| 89 |
))}
|
| 90 |
</select>
|
| 91 |
</label>
|
|
@@ -144,6 +229,11 @@ export default function Inspector({ onOcrSelected, onDelete }) {
|
|
| 144 |
return `${round(b.width)}×${round(b.height)} px · ${selectedAnn.points.length} точек · ${selectedAnn.source}`;
|
| 145 |
})()}
|
| 146 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
</div>
|
| 148 |
) : (
|
| 149 |
<div className="inspector-empty">Выберите элемент для редактирования</div>
|
|
@@ -175,14 +265,19 @@ export default function Inspector({ onOcrSelected, onDelete }) {
|
|
| 175 |
className={`ann-item${ann.id === selectedId ? ' active' : ''}`}
|
| 176 |
onClick={() => dispatch({ type: A.SELECT_ANNOTATION, payload: ann.id })}
|
| 177 |
>
|
| 178 |
-
<span className="ann-num" style={{ color:
|
| 179 |
-
{ann
|
| 180 |
</span>
|
| 181 |
<div className="ann-body">
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
<div className="ann-meta">
|
| 187 |
{ann.note && <span>{ann.note.slice(0, 30)}</span>}
|
| 188 |
{ann.contextPath && <span>{ann.contextPath.split('\\').pop()}</span>}
|
|
|
|
| 1 |
import { useCallback } from 'react';
|
| 2 |
import { useStore, useDispatch } from '../store/context';
|
| 3 |
import * as A from '../store/actions';
|
| 4 |
+
import { CATEGORY_SELECT_OPTIONS, CATEGORY_LABELS, CATEGORY_COLORS } from '../constants';
|
| 5 |
import { boundsOfPoints, polygonArea, round } from '../utils/geometry';
|
| 6 |
|
| 7 |
+
function annotationLabel(annotation) {
|
| 8 |
+
const detectedKind = String(annotation?.detectedKind || '').trim().toLowerCase();
|
| 9 |
+
const category = String(annotation?.category || '').trim().toLowerCase();
|
| 10 |
+
const isNumberedAuto = annotation?.source === 'auto' && (
|
| 11 |
+
detectedKind === 'widget'
|
| 12 |
+
|| detectedKind === 'shape'
|
| 13 |
+
|| detectedKind === 'indicator'
|
| 14 |
+
|| category === 'widget'
|
| 15 |
+
|| category === 'indicator'
|
| 16 |
+
);
|
| 17 |
+
if (annotation?.source === 'auto' && !isNumberedAuto) return '';
|
| 18 |
+
const displayNumber = Number.parseInt(String(annotation?.displayNumber ?? ''), 10);
|
| 19 |
+
if (Number.isFinite(displayNumber) && displayNumber > 0) return String(displayNumber);
|
| 20 |
+
const bindingUid = String(annotation?.bindingUid || '').trim();
|
| 21 |
+
if (bindingUid) return bindingUid;
|
| 22 |
+
if (annotation?.source === 'auto') return '';
|
| 23 |
+
const localNumber = Number.parseInt(String(annotation?.number ?? ''), 10);
|
| 24 |
+
if (Number.isFinite(localNumber) && localNumber > 0) return String(localNumber);
|
| 25 |
+
return '';
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
function inspectorMetaLabel(annotation) {
|
| 29 |
+
const publicLabel = annotationLabel(annotation);
|
| 30 |
+
if (publicLabel) return `#${publicLabel}`;
|
| 31 |
+
const localNumber = Number.parseInt(String(annotation?.number ?? ''), 10);
|
| 32 |
+
if (Number.isFinite(localNumber) && localNumber > 0) return `лок. #${localNumber}`;
|
| 33 |
+
return 'без номера';
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
function xmlStatusLabel(annotation) {
|
| 37 |
+
if (annotation?.xmlNeedsAttention) return 'XML: проверить';
|
| 38 |
+
if (annotation?.xmlExported) return annotation?.xmlMatched ? 'XML: экспортирован' : 'XML: экспортирован без Excel';
|
| 39 |
+
return '';
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
function annotationCategoryOptionId(annotation) {
|
| 43 |
+
const kind = String(annotation?.detectedKind || '').trim().toLowerCase();
|
| 44 |
+
const category = String(annotation?.category || '').trim().toLowerCase();
|
| 45 |
+
if (kind === 'shape') return 'static-shape';
|
| 46 |
+
if (kind === 'arrow') return 'static-arrow';
|
| 47 |
+
if (kind === 'form' || kind.startsWith('text-')) return 'static-form';
|
| 48 |
+
if (kind === 'widget' || category === 'widget') return 'widget';
|
| 49 |
+
if (category === 'static') return 'static-form';
|
| 50 |
+
return category || 'widget';
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
function annotationCategoryOption(annotation) {
|
| 54 |
+
const optionId = annotationCategoryOptionId(annotation);
|
| 55 |
+
return CATEGORY_SELECT_OPTIONS.find((option) => option.id === optionId) || null;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
function annotationCategoryLabel(annotation) {
|
| 59 |
+
const option = annotationCategoryOption(annotation);
|
| 60 |
+
if (option) return option.label;
|
| 61 |
+
return CATEGORY_LABELS[annotation?.category] || String(annotation?.category || 'Другое');
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
function annotationCategoryColor(annotation) {
|
| 65 |
+
const option = annotationCategoryOption(annotation);
|
| 66 |
+
if (option?.color) return option.color;
|
| 67 |
+
return CATEGORY_COLORS[annotation?.category] || CATEGORY_COLORS.other;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
export default function Inspector({ onOcrSelected, onDelete }) {
|
| 71 |
const state = useStore();
|
| 72 |
const dispatch = useDispatch();
|
|
|
|
| 82 |
});
|
| 83 |
}, [dispatch, selectedId]);
|
| 84 |
|
| 85 |
+
const updateCategoryOption = useCallback((optionId) => {
|
| 86 |
+
if (!selectedId) return;
|
| 87 |
+
const option = CATEGORY_SELECT_OPTIONS.find((item) => item.id === optionId);
|
| 88 |
+
if (!option) return;
|
| 89 |
+
dispatch({
|
| 90 |
+
type: A.UPDATE_ANNOTATION,
|
| 91 |
+
payload: {
|
| 92 |
+
id: selectedId,
|
| 93 |
+
changes: {
|
| 94 |
+
category: option.category,
|
| 95 |
+
detectedKind: option.detectedKind,
|
| 96 |
+
},
|
| 97 |
+
},
|
| 98 |
+
});
|
| 99 |
+
}, [dispatch, selectedId]);
|
| 100 |
+
|
| 101 |
const filtered = annotations.filter((a) => {
|
| 102 |
if (!filterText) return true;
|
| 103 |
const q = filterText.toLowerCase();
|
| 104 |
return (
|
| 105 |
String(a.number).includes(q)
|
| 106 |
+
|| String(a.displayNumber || '').includes(q)
|
| 107 |
|| (a.bindingUid || '').includes(q)
|
| 108 |
|| (a.note || '').toLowerCase().includes(q)
|
| 109 |
|| (a.category || '').toLowerCase().includes(q)
|
|
|
|
| 127 |
{selectedAnn ? (
|
| 128 |
<div className="inspector-editor">
|
| 129 |
<div className="inspector-badges">
|
| 130 |
+
<span className="badge" style={{ background: `${annotationCategoryColor(selectedAnn)}22`, color: annotationCategoryColor(selectedAnn) }}>
|
| 131 |
+
{annotationCategoryLabel(selectedAnn)}
|
| 132 |
</span>
|
| 133 |
+
<span className="inspector-meta">{inspectorMetaLabel(selectedAnn)}</span>
|
| 134 |
{selectedAnn.detectedKind && <span className="inspector-meta">{selectedAnn.detectedKind}</span>}
|
| 135 |
{selectedAnn.bindingUid && <span className="inspector-meta uid">UID {selectedAnn.bindingUid}</span>}
|
| 136 |
+
{xmlStatusLabel(selectedAnn) && (
|
| 137 |
+
<span className={`inspector-meta ${selectedAnn.xmlNeedsAttention ? 'xml-warn' : 'xml-ok'}`}>
|
| 138 |
+
{xmlStatusLabel(selectedAnn)}
|
| 139 |
+
</span>
|
| 140 |
+
)}
|
| 141 |
</div>
|
| 142 |
|
| 143 |
<div className="panel-grid">
|
|
|
|
| 166 |
<label className="field">
|
| 167 |
<span>Категория</span>
|
| 168 |
<select
|
| 169 |
+
value={annotationCategoryOptionId(selectedAnn)}
|
| 170 |
+
onChange={(e) => updateCategoryOption(e.target.value)}
|
| 171 |
>
|
| 172 |
+
{CATEGORY_SELECT_OPTIONS.map((option) => (
|
| 173 |
+
<option key={option.id} value={option.id}>{option.label}</option>
|
| 174 |
))}
|
| 175 |
</select>
|
| 176 |
</label>
|
|
|
|
| 229 |
return `${round(b.width)}×${round(b.height)} px · ${selectedAnn.points.length} точек · ${selectedAnn.source}`;
|
| 230 |
})()}
|
| 231 |
</div>
|
| 232 |
+
{!!selectedAnn.xmlMissingVisuals?.length && (
|
| 233 |
+
<div className="inspector-geo">
|
| 234 |
+
XML fallback: {selectedAnn.xmlMissingVisuals.join(', ')}
|
| 235 |
+
</div>
|
| 236 |
+
)}
|
| 237 |
</div>
|
| 238 |
) : (
|
| 239 |
<div className="inspector-empty">Выберите элемент для редактирования</div>
|
|
|
|
| 265 |
className={`ann-item${ann.id === selectedId ? ' active' : ''}`}
|
| 266 |
onClick={() => dispatch({ type: A.SELECT_ANNOTATION, payload: ann.id })}
|
| 267 |
>
|
| 268 |
+
<span className="ann-num" style={{ color: annotationCategoryColor(ann) }}>
|
| 269 |
+
{annotationLabel(ann)}
|
| 270 |
</span>
|
| 271 |
<div className="ann-body">
|
| 272 |
+
<div className="ann-title">
|
| 273 |
+
{annotationCategoryLabel(ann)}
|
| 274 |
+
{ann.bindingUid && <span className="ann-uid">UID {ann.bindingUid}</span>}
|
| 275 |
+
{xmlStatusLabel(ann) && (
|
| 276 |
+
<span className={`ann-xml-status ${ann.xmlNeedsAttention ? 'warn' : 'ok'}`}>
|
| 277 |
+
{ann.xmlNeedsAttention ? 'проверить' : 'xml'}
|
| 278 |
+
</span>
|
| 279 |
+
)}
|
| 280 |
+
</div>
|
| 281 |
<div className="ann-meta">
|
| 282 |
{ann.note && <span>{ann.note.slice(0, 30)}</span>}
|
| 283 |
{ann.contextPath && <span>{ann.contextPath.split('\\').pop()}</span>}
|
web-new/src/components/SvgWorkspace.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
| 2 |
import { useStore, useDispatch } from '../store/context';
|
| 3 |
import * as A from '../store/actions';
|
| 4 |
import { TOOLS, MODES, MIN_RECT_SIZE, LASSO_STEP, MOVE_THRESHOLD } from '../constants';
|
|
@@ -15,14 +15,31 @@ const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
| 15 |
const MIN_ZOOM = 0.1;
|
| 16 |
const MAX_ZOOM = 5;
|
| 17 |
const DETECTED_KIND_COLORS = Object.freeze({
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
arrow: '#ff4f87',
|
| 21 |
-
equipment: '#f97316',
|
| 22 |
indicator: '#22c55e',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
other: '#94a3b8',
|
| 24 |
});
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
function annotationColor(ann) {
|
| 27 |
if (ann.source === 'auto') {
|
| 28 |
const detected = String(ann.detectedKind || '').trim().toLowerCase();
|
|
@@ -36,12 +53,572 @@ function categoryFill(category) {
|
|
| 36 |
return CATEGORY_COLORS[category] || CATEGORY_COLORS.other;
|
| 37 |
}
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
export default function SvgWorkspace() {
|
| 40 |
const state = useStore();
|
| 41 |
const dispatch = useDispatch();
|
| 42 |
const {
|
| 43 |
interactionRef, findAnnotationAtPoint, createAnnotation,
|
| 44 |
-
updateAnnotationPoints,
|
| 45 |
} = useAnnotationTools();
|
| 46 |
|
| 47 |
const wrapRef = useRef(null);
|
|
@@ -51,10 +628,69 @@ export default function SvgWorkspace() {
|
|
| 51 |
const [tempRect, setTempRect] = useState(null);
|
| 52 |
const [tempPoints, setTempPoints] = useState([]);
|
| 53 |
const [pointerNow, setPointerNow] = useState(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
const isPanning = useRef(false);
|
| 55 |
const panStart = useRef({ x: 0, y: 0 });
|
| 56 |
|
| 57 |
const { imageWidth, imageHeight, imageDataUrl, tool, mode, annotations, selectedId } = state;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
useEffect(() => {
|
| 60 |
if (!imageWidth || !imageHeight || !wrapRef.current) return;
|
|
@@ -94,6 +730,26 @@ export default function SvgWorkspace() {
|
|
| 94 |
});
|
| 95 |
}, [dispatch]);
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
const handlePointerDown = useCallback((e) => {
|
| 98 |
const point = getSvgPoint(e);
|
| 99 |
const ir = interactionRef.current;
|
|
@@ -107,16 +763,40 @@ export default function SvgWorkspace() {
|
|
| 107 |
|
| 108 |
if (e.button !== 0) return;
|
| 109 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
const handleEl = e.target.closest('[data-handle-index]');
|
| 111 |
if (handleEl && tool === TOOLS.SELECT) {
|
| 112 |
const idx = parseInt(handleEl.dataset.handleIndex, 10);
|
| 113 |
const annId = handleEl.dataset.annotationId;
|
| 114 |
const ann = annotations.find((a) => a.id === annId);
|
| 115 |
if (ann) {
|
| 116 |
-
dispatch({ type: A.PUSH_HISTORY });
|
| 117 |
ir.dragVertexIndex = idx;
|
| 118 |
ir.dragTarget = annId;
|
| 119 |
ir.dragOriginalPoints = ann.points.map((p) => ({ ...p }));
|
|
|
|
|
|
|
|
|
|
| 120 |
dispatch({ type: A.SET_MODE, payload: MODES.VERTEX });
|
| 121 |
e.stopPropagation();
|
| 122 |
return;
|
|
@@ -128,14 +808,16 @@ export default function SvgWorkspace() {
|
|
| 128 |
if (hit) {
|
| 129 |
dispatch({ type: A.SELECT_ANNOTATION, payload: hit.id });
|
| 130 |
if (hit.id === selectedId) {
|
| 131 |
-
dispatch({ type: A.PUSH_HISTORY });
|
| 132 |
ir.dragTarget = hit.id;
|
| 133 |
ir.dragOriginalPoints = hit.points.map((p) => ({ ...p }));
|
| 134 |
ir.pointerStart = point;
|
| 135 |
ir.dragCommitted = false;
|
|
|
|
|
|
|
| 136 |
dispatch({ type: A.SET_MODE, payload: MODES.MOVE });
|
| 137 |
}
|
| 138 |
} else {
|
|
|
|
| 139 |
dispatch({ type: A.SELECT_ANNOTATION, payload: null });
|
| 140 |
}
|
| 141 |
return;
|
|
@@ -174,7 +856,18 @@ export default function SvgWorkspace() {
|
|
| 174 |
dispatch({ type: A.SET_MODE, payload: MODES.LASSO_DRAW });
|
| 175 |
return;
|
| 176 |
}
|
| 177 |
-
}, [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
const handlePointerMove = useCallback((e) => {
|
| 180 |
const point = getSvgPoint(e);
|
|
@@ -188,7 +881,9 @@ export default function SvgWorkspace() {
|
|
| 188 |
return;
|
| 189 |
}
|
| 190 |
|
| 191 |
-
|
|
|
|
|
|
|
| 192 |
|
| 193 |
if (mode === MODES.DRAW_RECT && ir.pointerStart) {
|
| 194 |
setTempRect({
|
|
@@ -212,38 +907,75 @@ export default function SvgWorkspace() {
|
|
| 212 |
return;
|
| 213 |
}
|
| 214 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
if (mode === MODES.MOVE && ir.dragTarget && ir.pointerStart) {
|
| 216 |
const dx = point.x - ir.pointerStart.x;
|
| 217 |
const dy = point.y - ir.pointerStart.y;
|
| 218 |
if (!ir.dragCommitted && Math.hypot(dx, dy) < MOVE_THRESHOLD) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
ir.dragCommitted = true;
|
| 220 |
const moved = ir.dragOriginalPoints.map((p) => ({
|
| 221 |
x: clamp(p.x + dx, 0, imageWidth),
|
| 222 |
y: clamp(p.y + dy, 0, imageHeight),
|
| 223 |
}));
|
| 224 |
-
|
| 225 |
-
type: A.UPDATE_ANNOTATION,
|
| 226 |
-
payload: { id: ir.dragTarget, changes: { points: moved } },
|
| 227 |
-
});
|
| 228 |
return;
|
| 229 |
}
|
| 230 |
|
| 231 |
if (mode === MODES.VERTEX && ir.dragTarget != null) {
|
| 232 |
const ann = annotations.find((a) => a.id === ir.dragTarget);
|
| 233 |
if (ann) {
|
| 234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
i === ir.dragVertexIndex
|
| 236 |
? { x: clamp(point.x, 0, imageWidth), y: clamp(point.y, 0, imageHeight) }
|
| 237 |
: p
|
| 238 |
);
|
| 239 |
-
|
| 240 |
-
type: A.UPDATE_ANNOTATION,
|
| 241 |
-
payload: { id: ir.dragTarget, changes: { points: newPoints } },
|
| 242 |
-
});
|
| 243 |
}
|
| 244 |
return;
|
| 245 |
}
|
| 246 |
-
}, [mode, getSvgPoint, imageWidth, imageHeight, dispatch, annotations, interactionRef]);
|
| 247 |
|
| 248 |
const handlePointerUp = useCallback(() => {
|
| 249 |
const ir = interactionRef.current;
|
|
@@ -284,20 +1016,55 @@ export default function SvgWorkspace() {
|
|
| 284 |
}
|
| 285 |
|
| 286 |
if (mode === MODES.MOVE) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
ir.dragTarget = null;
|
| 288 |
ir.dragOriginalPoints = null;
|
|
|
|
|
|
|
| 289 |
ir.dragCommitted = false;
|
|
|
|
|
|
|
| 290 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 291 |
return;
|
| 292 |
}
|
| 293 |
|
| 294 |
if (mode === MODES.VERTEX) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
ir.dragTarget = null;
|
| 296 |
ir.dragVertexIndex = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 298 |
return;
|
| 299 |
}
|
| 300 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
|
| 302 |
const finishPolygon = useCallback(() => {
|
| 303 |
const ir = interactionRef.current;
|
|
@@ -320,14 +1087,20 @@ export default function SvgWorkspace() {
|
|
| 320 |
interactionRef.current.tempPoints = [];
|
| 321 |
setTempPoints([]);
|
| 322 |
setTempRect(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 324 |
}
|
| 325 |
}
|
| 326 |
window.addEventListener('keydown', handleKey);
|
| 327 |
return () => window.removeEventListener('keydown', handleKey);
|
| 328 |
-
}, [mode, finishPolygon, dispatch, interactionRef]);
|
| 329 |
-
|
| 330 |
-
const scaleInvariant = useCallback((size) => size / zoom, [zoom]);
|
| 331 |
|
| 332 |
if (!imageDataUrl) {
|
| 333 |
return (
|
|
@@ -343,18 +1116,6 @@ export default function SvgWorkspace() {
|
|
| 343 |
const svgW = imageWidth * zoom;
|
| 344 |
const svgH = imageHeight * zoom;
|
| 345 |
|
| 346 |
-
const selectedAnn = annotations.find((a) => a.id === selectedId);
|
| 347 |
-
const sorted = [...annotations].sort((a, b) => polygonArea(b.points) - polygonArea(a.points));
|
| 348 |
-
const processingCounts = state.processing?.counts || {};
|
| 349 |
-
const processingSummary = [
|
| 350 |
-
`группы: ${Number(processingCounts.groups) || 0}`,
|
| 351 |
-
`ячейки: ${Number(processingCounts.cells) || 0}`,
|
| 352 |
-
`стрелки: ${Number(processingCounts.arrows) || 0}`,
|
| 353 |
-
`оборудование: ${Number(processingCounts.equipment) || 0}`,
|
| 354 |
-
`индикаторы: ${Number(processingCounts.indicators) || 0}`,
|
| 355 |
-
`прочее: ${Number(processingCounts.other) || 0}`,
|
| 356 |
-
].join(', ');
|
| 357 |
-
|
| 358 |
return (
|
| 359 |
<div className="viewer-panel" style={{ display: 'flex', flexDirection: 'column' }}>
|
| 360 |
<div
|
|
@@ -393,92 +1154,41 @@ export default function SvgWorkspace() {
|
|
| 393 |
</defs>
|
| 394 |
<image href={imageDataUrl} x="0" y="0" width={imageWidth} height={imageHeight} />
|
| 395 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 396 |
{/* Annotations layer */}
|
| 397 |
<g id="annotationsLayer">
|
| 398 |
{sorted.map((ann) => {
|
| 399 |
const isSelected = ann.id === selectedId;
|
| 400 |
-
const
|
| 401 |
-
const fillColor = strokeColor;
|
| 402 |
-
const opacity = 0.3 + (ann.confidence || 0.5) * 0.7;
|
| 403 |
-
const bounds = boundsOfPoints(ann.points);
|
| 404 |
-
const fontSize = Math.max(10, 13 / zoom);
|
| 405 |
-
const detectedKind = String(ann.detectedKind || '').trim().toLowerCase();
|
| 406 |
-
const showIndexLabel = detectedKind !== 'group';
|
| 407 |
-
const dashArray = detectedKind === 'group'
|
| 408 |
-
? `${8 / zoom} ${5 / zoom}`
|
| 409 |
-
: detectedKind === 'arrow'
|
| 410 |
-
? `${4 / zoom} ${3 / zoom}`
|
| 411 |
-
: 'none';
|
| 412 |
-
const strokeWidth = isSelected
|
| 413 |
-
? 2.5 / zoom
|
| 414 |
-
: detectedKind === 'group'
|
| 415 |
-
? 2.2 / zoom
|
| 416 |
-
: 1.8 / zoom;
|
| 417 |
-
|
| 418 |
return (
|
| 419 |
-
<
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
opacity={opacity}
|
| 427 |
-
/>
|
| 428 |
-
{/* Label */}
|
| 429 |
-
{showIndexLabel && (
|
| 430 |
-
<>
|
| 431 |
-
<circle
|
| 432 |
-
cx={bounds.x}
|
| 433 |
-
cy={bounds.y}
|
| 434 |
-
r={Math.max(8, 10 / zoom)}
|
| 435 |
-
fill={fillColor}
|
| 436 |
-
opacity="0.85"
|
| 437 |
-
filter="url(#labelShadow)"
|
| 438 |
-
/>
|
| 439 |
-
<text
|
| 440 |
-
x={bounds.x}
|
| 441 |
-
y={bounds.y}
|
| 442 |
-
textAnchor="middle"
|
| 443 |
-
dominantBaseline="central"
|
| 444 |
-
fill="white"
|
| 445 |
-
fontSize={fontSize}
|
| 446 |
-
fontWeight="bold"
|
| 447 |
-
stroke="rgba(0,0,0,0.4)"
|
| 448 |
-
strokeWidth={0.8 / zoom}
|
| 449 |
-
paintOrder="stroke"
|
| 450 |
-
>
|
| 451 |
-
{ann.number}
|
| 452 |
-
</text>
|
| 453 |
-
</>
|
| 454 |
-
)}
|
| 455 |
-
{/* Selection overlay */}
|
| 456 |
-
{isSelected && (
|
| 457 |
-
<>
|
| 458 |
-
<rect
|
| 459 |
-
x={bounds.x} y={bounds.y}
|
| 460 |
-
width={bounds.width} height={bounds.height}
|
| 461 |
-
fill="none"
|
| 462 |
-
stroke="rgba(255,255,255,0.5)"
|
| 463 |
-
strokeWidth={1 / zoom}
|
| 464 |
-
strokeDasharray={`${4 / zoom} ${3 / zoom}`}
|
| 465 |
-
/>
|
| 466 |
-
{ann.points.map((pt, i) => (
|
| 467 |
-
<circle
|
| 468 |
-
key={i}
|
| 469 |
-
cx={pt.x} cy={pt.y}
|
| 470 |
-
r={5 / zoom}
|
| 471 |
-
fill="white"
|
| 472 |
-
stroke="rgba(0,0,0,0.8)"
|
| 473 |
-
strokeWidth={1.5 / zoom}
|
| 474 |
-
data-handle-index={i}
|
| 475 |
-
data-annotation-id={ann.id}
|
| 476 |
-
style={{ cursor: 'move' }}
|
| 477 |
-
/>
|
| 478 |
-
))}
|
| 479 |
-
</>
|
| 480 |
-
)}
|
| 481 |
-
</g>
|
| 482 |
);
|
| 483 |
})}
|
| 484 |
</g>
|
|
|
|
| 1 |
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
| 2 |
import { useStore, useDispatch } from '../store/context';
|
| 3 |
import * as A from '../store/actions';
|
| 4 |
import { TOOLS, MODES, MIN_RECT_SIZE, LASSO_STEP, MOVE_THRESHOLD } from '../constants';
|
|
|
|
| 15 |
const MIN_ZOOM = 0.1;
|
| 16 |
const MAX_ZOOM = 5;
|
| 17 |
const DETECTED_KIND_COLORS = Object.freeze({
|
| 18 |
+
widget: '#3158ff',
|
| 19 |
+
form: '#00d71c',
|
| 20 |
+
shape: '#f97316',
|
| 21 |
arrow: '#ff4f87',
|
|
|
|
| 22 |
indicator: '#22c55e',
|
| 23 |
+
'text-label': '#e879f9',
|
| 24 |
+
'text-title': '#c026d3',
|
| 25 |
+
'text-equipment': '#f97316',
|
| 26 |
+
'text-parameter': '#06b6d4',
|
| 27 |
other: '#94a3b8',
|
| 28 |
});
|
| 29 |
|
| 30 |
+
const KIND_BADGE_LABELS = Object.freeze({
|
| 31 |
+
widget: 'В',
|
| 32 |
+
form: 'Ф',
|
| 33 |
+
shape: 'Ш',
|
| 34 |
+
arrow: 'С',
|
| 35 |
+
indicator: 'И',
|
| 36 |
+
'text-label': 'Т',
|
| 37 |
+
'text-title': 'Т',
|
| 38 |
+
'text-equipment': 'Т',
|
| 39 |
+
'text-parameter': 'Т',
|
| 40 |
+
other: '?',
|
| 41 |
+
});
|
| 42 |
+
|
| 43 |
function annotationColor(ann) {
|
| 44 |
if (ann.source === 'auto') {
|
| 45 |
const detected = String(ann.detectedKind || '').trim().toLowerCase();
|
|
|
|
| 53 |
return CATEGORY_COLORS[category] || CATEGORY_COLORS.other;
|
| 54 |
}
|
| 55 |
|
| 56 |
+
function isNumberedAutoAnnotation(ann) {
|
| 57 |
+
const detectedKind = String(ann?.detectedKind || '').trim().toLowerCase();
|
| 58 |
+
const category = String(ann?.category || '').trim().toLowerCase();
|
| 59 |
+
return (
|
| 60 |
+
detectedKind === 'widget'
|
| 61 |
+
|| detectedKind === 'shape'
|
| 62 |
+
|| detectedKind === 'indicator'
|
| 63 |
+
|| category === 'widget'
|
| 64 |
+
|| category === 'indicator'
|
| 65 |
+
);
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
function annotationLabel(ann) {
|
| 69 |
+
if (ann?.source === 'auto' && !isNumberedAutoAnnotation(ann)) return '';
|
| 70 |
+
const displayNumber = Number.parseInt(String(ann?.displayNumber ?? ''), 10);
|
| 71 |
+
if (Number.isFinite(displayNumber) && displayNumber > 0) return String(displayNumber);
|
| 72 |
+
const bindingUid = String(ann?.bindingUid || '').trim();
|
| 73 |
+
if (bindingUid) return bindingUid;
|
| 74 |
+
if (ann?.source === 'auto') return '';
|
| 75 |
+
const localNumber = Number.parseInt(String(ann?.number ?? ''), 10);
|
| 76 |
+
if (Number.isFinite(localNumber) && localNumber > 0) return String(localNumber);
|
| 77 |
+
return '';
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
function annotationXmlTone(ann) {
|
| 81 |
+
if (ann?.xmlNeedsAttention) return '#f59e0b';
|
| 82 |
+
if (ann?.xmlExported) return '#22c55e';
|
| 83 |
+
return '';
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
function basicShapeName(ann) {
|
| 87 |
+
return String(ann?.basicShape || '').trim().toLowerCase();
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
function isLibraryPlacedAnnotation(ann) {
|
| 91 |
+
return Boolean(
|
| 92 |
+
String(ann?.widgetNameOverride || '').trim()
|
| 93 |
+
|| String(ann?.staticShapeNameOverride || '').trim()
|
| 94 |
+
);
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
function annotationSourceCode(ann) {
|
| 98 |
+
if (ann?.source === 'auto') return 'A';
|
| 99 |
+
if (ann?.source === 'polygon') return 'P';
|
| 100 |
+
return 'M';
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
function annotationKindCode(ann) {
|
| 104 |
+
const detected = String(ann?.detectedKind || '').trim().toLowerCase();
|
| 105 |
+
return KIND_BADGE_LABELS[detected] || KIND_BADGE_LABELS.other;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
function annotationBadgeText(ann) {
|
| 109 |
+
return `${annotationSourceCode(ann)}:${annotationKindCode(ann)}`;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
function midpoint(a, b) {
|
| 113 |
+
return {
|
| 114 |
+
x: (Number(a?.x) + Number(b?.x)) / 2,
|
| 115 |
+
y: (Number(a?.y) + Number(b?.y)) / 2,
|
| 116 |
+
};
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
function rotatePointAround(point, center, angleDeg) {
|
| 120 |
+
const radians = (Number(angleDeg) * Math.PI) / 180;
|
| 121 |
+
const cos = Math.cos(radians);
|
| 122 |
+
const sin = Math.sin(radians);
|
| 123 |
+
const dx = point.x - center.x;
|
| 124 |
+
const dy = point.y - center.y;
|
| 125 |
+
return {
|
| 126 |
+
x: center.x + dx * cos - dy * sin,
|
| 127 |
+
y: center.y + dx * sin + dy * cos,
|
| 128 |
+
};
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
function rotatePointsAround(points, center, angleDeg) {
|
| 132 |
+
return (points || []).map((point) => rotatePointAround(point, center, angleDeg));
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
function rectFrame(points) {
|
| 136 |
+
if (!Array.isArray(points) || points.length !== 4) return null;
|
| 137 |
+
const [p0, p1, p2, p3] = points;
|
| 138 |
+
const edgeX = { x: p1.x - p0.x, y: p1.y - p0.y };
|
| 139 |
+
const edgeY = { x: p3.x - p0.x, y: p3.y - p0.y };
|
| 140 |
+
const width = Math.hypot(edgeX.x, edgeX.y);
|
| 141 |
+
const height = Math.hypot(edgeY.x, edgeY.y);
|
| 142 |
+
if (width < 1e-6 || height < 1e-6) return null;
|
| 143 |
+
return {
|
| 144 |
+
origin: { ...p0 },
|
| 145 |
+
center: midpoint(p0, p2),
|
| 146 |
+
edgeX,
|
| 147 |
+
edgeY,
|
| 148 |
+
width,
|
| 149 |
+
height,
|
| 150 |
+
axisX: { x: edgeX.x / width, y: edgeX.y / width },
|
| 151 |
+
axisY: { x: edgeY.x / height, y: edgeY.y / height },
|
| 152 |
+
rotation: (Math.atan2(edgeX.y, edgeX.x) * 180) / Math.PI,
|
| 153 |
+
};
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
function rectRotationFromPoints(points) {
|
| 157 |
+
const frame = rectFrame(points);
|
| 158 |
+
if (!frame) return 0;
|
| 159 |
+
let angle = frame.rotation % 360;
|
| 160 |
+
if (angle > 180) angle -= 360;
|
| 161 |
+
if (angle <= -180) angle += 360;
|
| 162 |
+
return round(angle, 2);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
function frameMatrix(frame, sourceWidth = frame?.width, sourceHeight = frame?.height) {
|
| 166 |
+
if (!frame) return '';
|
| 167 |
+
const sx = Math.max(1e-6, Number(sourceWidth) || frame.width || 1);
|
| 168 |
+
const sy = Math.max(1e-6, Number(sourceHeight) || frame.height || 1);
|
| 169 |
+
return `matrix(${round(frame.edgeX.x / sx, 5)} ${round(frame.edgeX.y / sx, 5)} ${round(frame.edgeY.x / sy, 5)} ${round(frame.edgeY.y / sy, 5)} ${round(frame.origin.x, 5)} ${round(frame.origin.y, 5)})`;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
function frameLocalToWorld(frame, localPoint) {
|
| 173 |
+
return {
|
| 174 |
+
x: frame.center.x + frame.axisX.x * localPoint.x + frame.axisY.x * localPoint.y,
|
| 175 |
+
y: frame.center.y + frame.axisX.y * localPoint.x + frame.axisY.y * localPoint.y,
|
| 176 |
+
};
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
function frameProjectPoint(frame, point) {
|
| 180 |
+
const dx = point.x - frame.center.x;
|
| 181 |
+
const dy = point.y - frame.center.y;
|
| 182 |
+
return {
|
| 183 |
+
x: dx * frame.axisX.x + dy * frame.axisX.y,
|
| 184 |
+
y: dx * frame.axisY.x + dy * frame.axisY.y,
|
| 185 |
+
};
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
function buildResizedRectPoints(points, handleIndex, point) {
|
| 189 |
+
const frame = rectFrame(points);
|
| 190 |
+
if (!frame || !Number.isFinite(handleIndex)) return points;
|
| 191 |
+
const halfWidth = frame.width / 2;
|
| 192 |
+
const halfHeight = frame.height / 2;
|
| 193 |
+
const localCorners = [
|
| 194 |
+
{ x: -halfWidth, y: -halfHeight },
|
| 195 |
+
{ x: halfWidth, y: -halfHeight },
|
| 196 |
+
{ x: halfWidth, y: halfHeight },
|
| 197 |
+
{ x: -halfWidth, y: halfHeight },
|
| 198 |
+
];
|
| 199 |
+
const anchor = localCorners[(handleIndex + 2) % 4];
|
| 200 |
+
const current = localCorners[handleIndex];
|
| 201 |
+
const pointerLocal = frameProjectPoint(frame, point);
|
| 202 |
+
const signX = Math.sign(current.x - anchor.x) || 1;
|
| 203 |
+
const signY = Math.sign(current.y - anchor.y) || 1;
|
| 204 |
+
if (Math.abs(pointerLocal.x - anchor.x) < MIN_RECT_SIZE) {
|
| 205 |
+
pointerLocal.x = anchor.x + signX * MIN_RECT_SIZE;
|
| 206 |
+
}
|
| 207 |
+
if (Math.abs(pointerLocal.y - anchor.y) < MIN_RECT_SIZE) {
|
| 208 |
+
pointerLocal.y = anchor.y + signY * MIN_RECT_SIZE;
|
| 209 |
+
}
|
| 210 |
+
const minX = Math.min(anchor.x, pointerLocal.x);
|
| 211 |
+
const maxX = Math.max(anchor.x, pointerLocal.x);
|
| 212 |
+
const minY = Math.min(anchor.y, pointerLocal.y);
|
| 213 |
+
const maxY = Math.max(anchor.y, pointerLocal.y);
|
| 214 |
+
return [
|
| 215 |
+
{ x: minX, y: minY },
|
| 216 |
+
{ x: maxX, y: minY },
|
| 217 |
+
{ x: maxX, y: maxY },
|
| 218 |
+
{ x: minX, y: maxY },
|
| 219 |
+
].map((local) => frameLocalToWorld(frame, local));
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
function rotateControl(points, zoom) {
|
| 223 |
+
if (!Array.isArray(points) || points.length !== 4) return null;
|
| 224 |
+
const topMid = midpoint(points[0], points[1]);
|
| 225 |
+
const center = midpoint(points[0], points[2]);
|
| 226 |
+
const vx = topMid.x - center.x;
|
| 227 |
+
const vy = topMid.y - center.y;
|
| 228 |
+
const length = Math.max(1e-6, Math.hypot(vx, vy));
|
| 229 |
+
const offset = 28 / zoom;
|
| 230 |
+
return {
|
| 231 |
+
topMid,
|
| 232 |
+
handle: {
|
| 233 |
+
x: topMid.x + (vx / length) * offset,
|
| 234 |
+
y: topMid.y + (vy / length) * offset,
|
| 235 |
+
},
|
| 236 |
+
};
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
function isTransformableAnnotation(ann, points) {
|
| 240 |
+
return ann?.source === 'manual' && ann?.type === 'rect' && Array.isArray(points) && points.length === 4;
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
const AnnotationNode = memo(function AnnotationNode({
|
| 244 |
+
ann,
|
| 245 |
+
points,
|
| 246 |
+
isSelected,
|
| 247 |
+
zoom,
|
| 248 |
+
}) {
|
| 249 |
+
const strokeColor = annotationColor(ann);
|
| 250 |
+
const fillColor = strokeColor;
|
| 251 |
+
const opacity = 0.3 + (ann.confidence || 0.5) * 0.7;
|
| 252 |
+
const fontSize = Math.max(10, 13 / zoom);
|
| 253 |
+
const detectedKind = String(ann.detectedKind || '').trim().toLowerCase();
|
| 254 |
+
const xmlTone = annotationXmlTone(ann);
|
| 255 |
+
const showIndexLabel = detectedKind !== 'form' && detectedKind !== 'arrow';
|
| 256 |
+
const labelText = annotationLabel(ann);
|
| 257 |
+
const showLibraryPreview = ann?.source === 'manual' && isLibraryPlacedAnnotation(ann);
|
| 258 |
+
const annotationBoundsBox = boundsOfPoints(points);
|
| 259 |
+
const libraryTitle = String(
|
| 260 |
+
ann?.note
|
| 261 |
+
|| ann?.widgetNameOverride
|
| 262 |
+
|| ann?.staticShapeNameOverride
|
| 263 |
+
|| ''
|
| 264 |
+
).trim();
|
| 265 |
+
const dashArray = detectedKind === 'form'
|
| 266 |
+
? `${8 / zoom} ${5 / zoom}`
|
| 267 |
+
: detectedKind === 'arrow'
|
| 268 |
+
? `${4 / zoom} ${3 / zoom}`
|
| 269 |
+
: 'none';
|
| 270 |
+
const isManual = ann.source === 'manual';
|
| 271 |
+
const isAuto = ann.source === 'auto';
|
| 272 |
+
const frame = rectFrame(points);
|
| 273 |
+
const baseShape = basicShapeName(ann);
|
| 274 |
+
const transformable = isSelected && isTransformableAnnotation(ann, points);
|
| 275 |
+
const rotateHandle = transformable ? rotateControl(points, zoom) : null;
|
| 276 |
+
const strokeWidth = isSelected
|
| 277 |
+
? 2.5 / zoom
|
| 278 |
+
: isManual
|
| 279 |
+
? 2.8 / zoom
|
| 280 |
+
: detectedKind === 'form'
|
| 281 |
+
? 2.2 / zoom
|
| 282 |
+
: 1.8 / zoom;
|
| 283 |
+
const haloWidth = isSelected
|
| 284 |
+
? 7 / zoom
|
| 285 |
+
: isManual
|
| 286 |
+
? 6 / zoom
|
| 287 |
+
: 4.5 / zoom;
|
| 288 |
+
const baseFillOpacity = isSelected
|
| 289 |
+
? 0.28
|
| 290 |
+
: isManual
|
| 291 |
+
? 0.24
|
| 292 |
+
: detectedKind === 'arrow'
|
| 293 |
+
? 0.0
|
| 294 |
+
: detectedKind === 'form'
|
| 295 |
+
? 0.12
|
| 296 |
+
: 0.18;
|
| 297 |
+
const shapeFill = detectedKind === 'arrow' ? 'none' : `${fillColor}${Math.round(baseFillOpacity * 255).toString(16).padStart(2, '0')}`;
|
| 298 |
+
const sourceBadgeText = annotationBadgeText(ann);
|
| 299 |
+
const badgeWidth = Math.max(18, sourceBadgeText.length * (6.6 / zoom) + 8 / zoom);
|
| 300 |
+
const badgeHeight = Math.max(11, 13 / zoom);
|
| 301 |
+
const badgeX = annotationBoundsBox.x + 2 / zoom;
|
| 302 |
+
const badgeY = annotationBoundsBox.y + 2 / zoom;
|
| 303 |
+
const badgeFill = isManual ? 'rgba(15,23,42,0.88)' : 'rgba(15,23,42,0.72)';
|
| 304 |
+
const badgeStroke = isManual ? 'rgba(255,255,255,0.9)' : `${strokeColor}cc`;
|
| 305 |
+
const hasIntrinsicShape = Boolean(frame && (String(ann?.svgPath || '').trim() || baseShape));
|
| 306 |
+
const vectorMatrix = frame ? frameMatrix(
|
| 307 |
+
frame,
|
| 308 |
+
Number(ann?.svgWidth) || frame.width,
|
| 309 |
+
Number(ann?.svgHeight) || frame.height,
|
| 310 |
+
) : '';
|
| 311 |
+
const shapeMatrix = frame ? frameMatrix(frame, frame.width, frame.height) : '';
|
| 312 |
+
const shapeStroke = isSelected ? '#fff' : strokeColor;
|
| 313 |
+
|
| 314 |
+
return (
|
| 315 |
+
<g data-id={ann.id}>
|
| 316 |
+
{!hasIntrinsicShape && (detectedKind === 'arrow' ? (
|
| 317 |
+
<path
|
| 318 |
+
d={polylineFromPoints(points)}
|
| 319 |
+
fill="none"
|
| 320 |
+
stroke={`${strokeColor}${isManual ? '55' : '33'}`}
|
| 321 |
+
strokeWidth={haloWidth}
|
| 322 |
+
strokeLinecap="round"
|
| 323 |
+
strokeLinejoin="round"
|
| 324 |
+
opacity={0.95}
|
| 325 |
+
/>
|
| 326 |
+
) : (
|
| 327 |
+
<path
|
| 328 |
+
d={pathFromPoints(points)}
|
| 329 |
+
fill={shapeFill}
|
| 330 |
+
stroke={`${strokeColor}${isManual ? '66' : '40'}`}
|
| 331 |
+
strokeWidth={haloWidth}
|
| 332 |
+
strokeLinejoin="round"
|
| 333 |
+
opacity={0.9}
|
| 334 |
+
/>
|
| 335 |
+
))}
|
| 336 |
+
{xmlTone && (
|
| 337 |
+
<path
|
| 338 |
+
d={pathFromPoints(points)}
|
| 339 |
+
fill="none"
|
| 340 |
+
stroke={xmlTone}
|
| 341 |
+
strokeWidth={(ann?.xmlNeedsAttention ? 3 : 2) / zoom}
|
| 342 |
+
strokeDasharray={ann?.xmlNeedsAttention ? `${6 / zoom} ${4 / zoom}` : `${3 / zoom} ${3 / zoom}`}
|
| 343 |
+
opacity={0.95}
|
| 344 |
+
/>
|
| 345 |
+
)}
|
| 346 |
+
{(() => {
|
| 347 |
+
const common = {
|
| 348 |
+
stroke: shapeStroke,
|
| 349 |
+
strokeWidth,
|
| 350 |
+
opacity,
|
| 351 |
+
};
|
| 352 |
+
if (frame && String(ann?.svgPath || '').trim()) {
|
| 353 |
+
return (
|
| 354 |
+
<path
|
| 355 |
+
d={ann.svgPath}
|
| 356 |
+
transform={vectorMatrix}
|
| 357 |
+
fill="none"
|
| 358 |
+
stroke={shapeStroke}
|
| 359 |
+
strokeWidth={Math.max(strokeWidth, 2.2 / zoom)}
|
| 360 |
+
strokeLinejoin="round"
|
| 361 |
+
strokeLinecap="round"
|
| 362 |
+
opacity={1}
|
| 363 |
+
/>
|
| 364 |
+
);
|
| 365 |
+
}
|
| 366 |
+
if (frame && baseShape === 'ellipse') {
|
| 367 |
+
return (
|
| 368 |
+
<ellipse
|
| 369 |
+
cx={frame.width / 2}
|
| 370 |
+
cy={frame.height / 2}
|
| 371 |
+
rx={Math.max(1, frame.width / 2)}
|
| 372 |
+
ry={Math.max(1, frame.height / 2)}
|
| 373 |
+
fill={isSelected ? `${fillColor}22` : 'none'}
|
| 374 |
+
transform={shapeMatrix}
|
| 375 |
+
{...common}
|
| 376 |
+
/>
|
| 377 |
+
);
|
| 378 |
+
}
|
| 379 |
+
if (frame && (baseShape === 'line' || baseShape === 'arrow')) {
|
| 380 |
+
const x1 = 0;
|
| 381 |
+
const y1 = frame.height;
|
| 382 |
+
const x2 = frame.width;
|
| 383 |
+
const y2 = 0;
|
| 384 |
+
return (
|
| 385 |
+
<>
|
| 386 |
+
<line x1={x1} y1={y1} x2={x2} y2={y2} fill="none" transform={shapeMatrix} {...common} />
|
| 387 |
+
{baseShape === 'arrow' && (
|
| 388 |
+
<polyline
|
| 389 |
+
points={`${x2 - (8 / zoom)},${y2 + (2 / zoom)} ${x2},${y2} ${x2 - (2 / zoom)},${y2 + (8 / zoom)}`}
|
| 390 |
+
fill="none"
|
| 391 |
+
stroke={shapeStroke}
|
| 392 |
+
strokeWidth={strokeWidth}
|
| 393 |
+
opacity={opacity}
|
| 394 |
+
transform={shapeMatrix}
|
| 395 |
+
/>
|
| 396 |
+
)}
|
| 397 |
+
</>
|
| 398 |
+
);
|
| 399 |
+
}
|
| 400 |
+
if (frame && baseShape === 'table') {
|
| 401 |
+
const bw = Math.max(2, frame.width);
|
| 402 |
+
const bh = Math.max(2, frame.height);
|
| 403 |
+
return (
|
| 404 |
+
<>
|
| 405 |
+
<rect x="0" y="0" width={bw} height={bh} fill="none" transform={shapeMatrix} {...common} />
|
| 406 |
+
<line x1="0" y1={bh * 0.35} x2={bw} y2={bh * 0.35} fill="none" transform={shapeMatrix} {...common} />
|
| 407 |
+
<line x1={bw * 0.5} y1={bh * 0.35} x2={bw * 0.5} y2={bh} fill="none" transform={shapeMatrix} {...common} />
|
| 408 |
+
</>
|
| 409 |
+
);
|
| 410 |
+
}
|
| 411 |
+
if (frame && baseShape === 'text') {
|
| 412 |
+
return (
|
| 413 |
+
<text
|
| 414 |
+
x={frame.width / 2}
|
| 415 |
+
y={frame.height / 2}
|
| 416 |
+
transform={shapeMatrix}
|
| 417 |
+
textAnchor="middle"
|
| 418 |
+
dominantBaseline="central"
|
| 419 |
+
fill={shapeStroke}
|
| 420 |
+
fontSize={Math.max(10, 14 / zoom)}
|
| 421 |
+
fontWeight="600"
|
| 422 |
+
>
|
| 423 |
+
{libraryTitle || 'Текст'}
|
| 424 |
+
</text>
|
| 425 |
+
);
|
| 426 |
+
}
|
| 427 |
+
const manualFill = isManual ? `${fillColor}55` : shapeFill;
|
| 428 |
+
if (detectedKind === 'arrow') {
|
| 429 |
+
return (
|
| 430 |
+
<path
|
| 431 |
+
d={polylineFromPoints(points)}
|
| 432 |
+
fill="none"
|
| 433 |
+
stroke={shapeStroke}
|
| 434 |
+
strokeWidth={Math.max(strokeWidth, 2.2 / zoom)}
|
| 435 |
+
strokeDasharray={isSelected ? `${4 / zoom} ${3 / zoom}` : 'none'}
|
| 436 |
+
strokeLinecap="round"
|
| 437 |
+
strokeLinejoin="round"
|
| 438 |
+
opacity={1}
|
| 439 |
+
/>
|
| 440 |
+
);
|
| 441 |
+
}
|
| 442 |
+
return (
|
| 443 |
+
<path
|
| 444 |
+
d={pathFromPoints(points)}
|
| 445 |
+
fill={isSelected ? `${fillColor}33` : (showLibraryPreview ? `${fillColor}38` : manualFill)}
|
| 446 |
+
stroke={shapeStroke}
|
| 447 |
+
strokeWidth={strokeWidth}
|
| 448 |
+
strokeDasharray={isSelected ? `${4 / zoom} ${3 / zoom}` : (isManual ? 'none' : dashArray)}
|
| 449 |
+
opacity={isManual ? 1 : opacity}
|
| 450 |
+
/>
|
| 451 |
+
);
|
| 452 |
+
})()}
|
| 453 |
+
<g opacity={isSelected ? 1 : (isAuto ? 0.9 : 1)}>
|
| 454 |
+
<rect
|
| 455 |
+
x={badgeX}
|
| 456 |
+
y={badgeY}
|
| 457 |
+
rx={Math.max(2, 3 / zoom)}
|
| 458 |
+
ry={Math.max(2, 3 / zoom)}
|
| 459 |
+
width={badgeWidth}
|
| 460 |
+
height={badgeHeight}
|
| 461 |
+
fill={badgeFill}
|
| 462 |
+
stroke={badgeStroke}
|
| 463 |
+
strokeWidth={1 / zoom}
|
| 464 |
+
/>
|
| 465 |
+
<text
|
| 466 |
+
x={badgeX + badgeWidth / 2}
|
| 467 |
+
y={badgeY + badgeHeight / 2}
|
| 468 |
+
textAnchor="middle"
|
| 469 |
+
dominantBaseline="central"
|
| 470 |
+
fill="white"
|
| 471 |
+
fontSize={Math.max(8, 9 / zoom)}
|
| 472 |
+
fontWeight="700"
|
| 473 |
+
letterSpacing="0.02em"
|
| 474 |
+
>
|
| 475 |
+
{sourceBadgeText}
|
| 476 |
+
</text>
|
| 477 |
+
</g>
|
| 478 |
+
{showLibraryPreview && !String(ann?.svgPath || '').trim() && baseShape !== 'text' && libraryTitle && (
|
| 479 |
+
<text
|
| 480 |
+
x={annotationBoundsBox.x + annotationBoundsBox.width / 2}
|
| 481 |
+
y={annotationBoundsBox.y + annotationBoundsBox.height / 2}
|
| 482 |
+
textAnchor="middle"
|
| 483 |
+
dominantBaseline="central"
|
| 484 |
+
fill={fillColor}
|
| 485 |
+
fontSize={Math.max(9, 11 / zoom)}
|
| 486 |
+
fontWeight="600"
|
| 487 |
+
stroke="rgba(15,23,42,0.55)"
|
| 488 |
+
strokeWidth={0.7 / zoom}
|
| 489 |
+
paintOrder="stroke"
|
| 490 |
+
>
|
| 491 |
+
{libraryTitle.slice(0, 20)}
|
| 492 |
+
</text>
|
| 493 |
+
)}
|
| 494 |
+
{showIndexLabel && labelText && (
|
| 495 |
+
<>
|
| 496 |
+
<circle
|
| 497 |
+
cx={annotationBoundsBox.x}
|
| 498 |
+
cy={annotationBoundsBox.y}
|
| 499 |
+
r={Math.max(8, 10 / zoom)}
|
| 500 |
+
fill={fillColor}
|
| 501 |
+
opacity="0.85"
|
| 502 |
+
filter="url(#labelShadow)"
|
| 503 |
+
/>
|
| 504 |
+
<text
|
| 505 |
+
x={annotationBoundsBox.x}
|
| 506 |
+
y={annotationBoundsBox.y}
|
| 507 |
+
textAnchor="middle"
|
| 508 |
+
dominantBaseline="central"
|
| 509 |
+
fill="white"
|
| 510 |
+
fontSize={fontSize}
|
| 511 |
+
fontWeight="bold"
|
| 512 |
+
stroke="rgba(0,0,0,0.4)"
|
| 513 |
+
strokeWidth={0.8 / zoom}
|
| 514 |
+
paintOrder="stroke"
|
| 515 |
+
>
|
| 516 |
+
{labelText}
|
| 517 |
+
</text>
|
| 518 |
+
</>
|
| 519 |
+
)}
|
| 520 |
+
{ann?.xmlNeedsAttention && (
|
| 521 |
+
<circle
|
| 522 |
+
cx={annotationBoundsBox.x + annotationBoundsBox.width}
|
| 523 |
+
cy={annotationBoundsBox.y}
|
| 524 |
+
r={Math.max(4, 5 / zoom)}
|
| 525 |
+
fill="#f59e0b"
|
| 526 |
+
stroke="rgba(15,23,42,0.95)"
|
| 527 |
+
strokeWidth={1.4 / zoom}
|
| 528 |
+
/>
|
| 529 |
+
)}
|
| 530 |
+
{transformable ? (
|
| 531 |
+
<>
|
| 532 |
+
<path
|
| 533 |
+
d={pathFromPoints(points)}
|
| 534 |
+
fill="none"
|
| 535 |
+
stroke="rgba(255,255,255,0.58)"
|
| 536 |
+
strokeWidth={1 / zoom}
|
| 537 |
+
strokeDasharray={`${4 / zoom} ${3 / zoom}`}
|
| 538 |
+
/>
|
| 539 |
+
{points.map((pt, i) => (
|
| 540 |
+
<rect
|
| 541 |
+
key={i}
|
| 542 |
+
x={pt.x - (5.5 / zoom)}
|
| 543 |
+
y={pt.y - (5.5 / zoom)}
|
| 544 |
+
width={11 / zoom}
|
| 545 |
+
height={11 / zoom}
|
| 546 |
+
rx={2.2 / zoom}
|
| 547 |
+
fill="white"
|
| 548 |
+
stroke="rgba(0,0,0,0.8)"
|
| 549 |
+
strokeWidth={1.5 / zoom}
|
| 550 |
+
data-transform-handle={`resize-${i}`}
|
| 551 |
+
data-annotation-id={ann.id}
|
| 552 |
+
style={{ cursor: 'nwse-resize' }}
|
| 553 |
+
/>
|
| 554 |
+
))}
|
| 555 |
+
{rotateHandle && (
|
| 556 |
+
<>
|
| 557 |
+
<line
|
| 558 |
+
x1={rotateHandle.topMid.x}
|
| 559 |
+
y1={rotateHandle.topMid.y}
|
| 560 |
+
x2={rotateHandle.handle.x}
|
| 561 |
+
y2={rotateHandle.handle.y}
|
| 562 |
+
stroke="rgba(255,255,255,0.8)"
|
| 563 |
+
strokeWidth={1.2 / zoom}
|
| 564 |
+
/>
|
| 565 |
+
<circle
|
| 566 |
+
cx={rotateHandle.handle.x}
|
| 567 |
+
cy={rotateHandle.handle.y}
|
| 568 |
+
r={6 / zoom}
|
| 569 |
+
fill="#0f172a"
|
| 570 |
+
stroke="white"
|
| 571 |
+
strokeWidth={1.5 / zoom}
|
| 572 |
+
data-transform-handle="rotate"
|
| 573 |
+
data-annotation-id={ann.id}
|
| 574 |
+
style={{ cursor: 'grab' }}
|
| 575 |
+
/>
|
| 576 |
+
</>
|
| 577 |
+
)}
|
| 578 |
+
</>
|
| 579 |
+
) : isSelected && (
|
| 580 |
+
<>
|
| 581 |
+
<rect
|
| 582 |
+
x={annotationBoundsBox.x}
|
| 583 |
+
y={annotationBoundsBox.y}
|
| 584 |
+
width={annotationBoundsBox.width}
|
| 585 |
+
height={annotationBoundsBox.height}
|
| 586 |
+
fill="none"
|
| 587 |
+
stroke="rgba(255,255,255,0.5)"
|
| 588 |
+
strokeWidth={1 / zoom}
|
| 589 |
+
strokeDasharray={`${4 / zoom} ${3 / zoom}`}
|
| 590 |
+
/>
|
| 591 |
+
{points.map((pt, i) => (
|
| 592 |
+
<circle
|
| 593 |
+
key={i}
|
| 594 |
+
cx={pt.x}
|
| 595 |
+
cy={pt.y}
|
| 596 |
+
r={5 / zoom}
|
| 597 |
+
fill="white"
|
| 598 |
+
stroke="rgba(0,0,0,0.8)"
|
| 599 |
+
strokeWidth={1.5 / zoom}
|
| 600 |
+
data-handle-index={i}
|
| 601 |
+
data-annotation-id={ann.id}
|
| 602 |
+
style={{ cursor: 'move' }}
|
| 603 |
+
/>
|
| 604 |
+
))}
|
| 605 |
+
</>
|
| 606 |
+
)}
|
| 607 |
+
</g>
|
| 608 |
+
);
|
| 609 |
+
}, (prev, next) => (
|
| 610 |
+
prev.ann === next.ann
|
| 611 |
+
&& prev.points === next.points
|
| 612 |
+
&& prev.isSelected === next.isSelected
|
| 613 |
+
&& prev.zoom === next.zoom
|
| 614 |
+
));
|
| 615 |
+
|
| 616 |
export default function SvgWorkspace() {
|
| 617 |
const state = useStore();
|
| 618 |
const dispatch = useDispatch();
|
| 619 |
const {
|
| 620 |
interactionRef, findAnnotationAtPoint, createAnnotation,
|
| 621 |
+
updateAnnotationPoints,
|
| 622 |
} = useAnnotationTools();
|
| 623 |
|
| 624 |
const wrapRef = useRef(null);
|
|
|
|
| 628 |
const [tempRect, setTempRect] = useState(null);
|
| 629 |
const [tempPoints, setTempPoints] = useState([]);
|
| 630 |
const [pointerNow, setPointerNow] = useState(null);
|
| 631 |
+
const [draftPoints, setDraftPoints] = useState(null);
|
| 632 |
+
const draftPointsRef = useRef(null);
|
| 633 |
+
const draftFrameRef = useRef(0);
|
| 634 |
+
const pendingDraftPointsRef = useRef(null);
|
| 635 |
const isPanning = useRef(false);
|
| 636 |
const panStart = useRef({ x: 0, y: 0 });
|
| 637 |
|
| 638 |
const { imageWidth, imageHeight, imageDataUrl, tool, mode, annotations, selectedId } = state;
|
| 639 |
+
const selectedAnn = annotations.find((a) => a.id === selectedId) || null;
|
| 640 |
+
const sorted = useMemo(
|
| 641 |
+
() => [...annotations].sort((a, b) => polygonArea(b.points) - polygonArea(a.points)),
|
| 642 |
+
[annotations],
|
| 643 |
+
);
|
| 644 |
+
const processingCounts = state.processing?.counts || {};
|
| 645 |
+
const processingSummary = [
|
| 646 |
+
`виджеты: ${Number(processingCounts.widgets) || Number(processingCounts.cells) || 0}`,
|
| 647 |
+
`формы: ${Number(processingCounts.forms) || Number(processingCounts.groups) || 0}`,
|
| 648 |
+
`стрелки: ${Number(processingCounts.arrows) || 0}`,
|
| 649 |
+
`шейпы: ${Number(processingCounts.shapes) || Number(processingCounts.equipment) || 0}`,
|
| 650 |
+
`индикаторы: ${Number(processingCounts.indicators) || 0}`,
|
| 651 |
+
`прочее: ${Number(processingCounts.other) || 0}`,
|
| 652 |
+
].join(', ');
|
| 653 |
+
|
| 654 |
+
const setDraftPointsImmediate = useCallback((points) => {
|
| 655 |
+
const normalized = Array.isArray(points) ? points.map((p) => ({ ...p })) : null;
|
| 656 |
+
draftPointsRef.current = normalized;
|
| 657 |
+
pendingDraftPointsRef.current = null;
|
| 658 |
+
if (draftFrameRef.current) {
|
| 659 |
+
cancelAnimationFrame(draftFrameRef.current);
|
| 660 |
+
draftFrameRef.current = 0;
|
| 661 |
+
}
|
| 662 |
+
setDraftPoints(normalized);
|
| 663 |
+
}, []);
|
| 664 |
+
|
| 665 |
+
const scheduleDraftPoints = useCallback((points) => {
|
| 666 |
+
const normalized = Array.isArray(points) ? points.map((p) => ({ ...p })) : null;
|
| 667 |
+
draftPointsRef.current = normalized;
|
| 668 |
+
pendingDraftPointsRef.current = normalized;
|
| 669 |
+
if (draftFrameRef.current) return;
|
| 670 |
+
draftFrameRef.current = requestAnimationFrame(() => {
|
| 671 |
+
draftFrameRef.current = 0;
|
| 672 |
+
const pending = pendingDraftPointsRef.current;
|
| 673 |
+
pendingDraftPointsRef.current = null;
|
| 674 |
+
setDraftPoints(pending);
|
| 675 |
+
});
|
| 676 |
+
}, []);
|
| 677 |
+
|
| 678 |
+
const clearDraftPoints = useCallback(() => {
|
| 679 |
+
draftPointsRef.current = null;
|
| 680 |
+
pendingDraftPointsRef.current = null;
|
| 681 |
+
if (draftFrameRef.current) {
|
| 682 |
+
cancelAnimationFrame(draftFrameRef.current);
|
| 683 |
+
draftFrameRef.current = 0;
|
| 684 |
+
}
|
| 685 |
+
setDraftPoints(null);
|
| 686 |
+
}, []);
|
| 687 |
+
|
| 688 |
+
useEffect(() => () => {
|
| 689 |
+
if (draftFrameRef.current) {
|
| 690 |
+
cancelAnimationFrame(draftFrameRef.current);
|
| 691 |
+
draftFrameRef.current = 0;
|
| 692 |
+
}
|
| 693 |
+
}, []);
|
| 694 |
|
| 695 |
useEffect(() => {
|
| 696 |
if (!imageWidth || !imageHeight || !wrapRef.current) return;
|
|
|
|
| 730 |
});
|
| 731 |
}, [dispatch]);
|
| 732 |
|
| 733 |
+
const commitAnnotationGeometry = useCallback((annotation, nextPoints) => {
|
| 734 |
+
if (!annotation || !Array.isArray(nextPoints) || !nextPoints.length) return;
|
| 735 |
+
const clampedPoints = nextPoints.map((point) => ({
|
| 736 |
+
x: clamp(Number(point.x), 0, imageWidth),
|
| 737 |
+
y: clamp(Number(point.y), 0, imageHeight),
|
| 738 |
+
}));
|
| 739 |
+
dispatch({
|
| 740 |
+
type: A.UPDATE_ANNOTATION,
|
| 741 |
+
payload: {
|
| 742 |
+
id: annotation.id,
|
| 743 |
+
changes: {
|
| 744 |
+
points: clampedPoints,
|
| 745 |
+
rotation: annotation.type === 'rect' ? rectRotationFromPoints(clampedPoints) : 0,
|
| 746 |
+
reviewed: true,
|
| 747 |
+
reviewedAt: Date.now(),
|
| 748 |
+
},
|
| 749 |
+
},
|
| 750 |
+
});
|
| 751 |
+
}, [dispatch, imageWidth, imageHeight]);
|
| 752 |
+
|
| 753 |
const handlePointerDown = useCallback((e) => {
|
| 754 |
const point = getSvgPoint(e);
|
| 755 |
const ir = interactionRef.current;
|
|
|
|
| 763 |
|
| 764 |
if (e.button !== 0) return;
|
| 765 |
|
| 766 |
+
const transformHandleEl = e.target.closest('[data-transform-handle]');
|
| 767 |
+
if (transformHandleEl && tool === TOOLS.SELECT) {
|
| 768 |
+
const annId = transformHandleEl.dataset.annotationId;
|
| 769 |
+
const ann = annotations.find((item) => item.id === annId);
|
| 770 |
+
if (ann && isTransformableAnnotation(ann, ann.points)) {
|
| 771 |
+
ir.transformHandle = String(transformHandleEl.dataset.transformHandle || '');
|
| 772 |
+
ir.dragTarget = annId;
|
| 773 |
+
ir.dragOriginalPoints = ann.points.map((p) => ({ ...p }));
|
| 774 |
+
ir.dragOriginalRotation = rectRotationFromPoints(ann.points);
|
| 775 |
+
ir.pointerStart = point;
|
| 776 |
+
ir.dragCommitted = false;
|
| 777 |
+
ir.historyPushed = false;
|
| 778 |
+
setDraftPointsImmediate(ann.points);
|
| 779 |
+
dispatch({
|
| 780 |
+
type: A.SET_MODE,
|
| 781 |
+
payload: ir.transformHandle === 'rotate' ? MODES.ROTATE : MODES.RESIZE,
|
| 782 |
+
});
|
| 783 |
+
e.stopPropagation();
|
| 784 |
+
return;
|
| 785 |
+
}
|
| 786 |
+
}
|
| 787 |
+
|
| 788 |
const handleEl = e.target.closest('[data-handle-index]');
|
| 789 |
if (handleEl && tool === TOOLS.SELECT) {
|
| 790 |
const idx = parseInt(handleEl.dataset.handleIndex, 10);
|
| 791 |
const annId = handleEl.dataset.annotationId;
|
| 792 |
const ann = annotations.find((a) => a.id === annId);
|
| 793 |
if (ann) {
|
|
|
|
| 794 |
ir.dragVertexIndex = idx;
|
| 795 |
ir.dragTarget = annId;
|
| 796 |
ir.dragOriginalPoints = ann.points.map((p) => ({ ...p }));
|
| 797 |
+
ir.dragCommitted = false;
|
| 798 |
+
ir.historyPushed = false;
|
| 799 |
+
setDraftPointsImmediate(ann.points);
|
| 800 |
dispatch({ type: A.SET_MODE, payload: MODES.VERTEX });
|
| 801 |
e.stopPropagation();
|
| 802 |
return;
|
|
|
|
| 808 |
if (hit) {
|
| 809 |
dispatch({ type: A.SELECT_ANNOTATION, payload: hit.id });
|
| 810 |
if (hit.id === selectedId) {
|
|
|
|
| 811 |
ir.dragTarget = hit.id;
|
| 812 |
ir.dragOriginalPoints = hit.points.map((p) => ({ ...p }));
|
| 813 |
ir.pointerStart = point;
|
| 814 |
ir.dragCommitted = false;
|
| 815 |
+
ir.historyPushed = false;
|
| 816 |
+
setDraftPointsImmediate(hit.points);
|
| 817 |
dispatch({ type: A.SET_MODE, payload: MODES.MOVE });
|
| 818 |
}
|
| 819 |
} else {
|
| 820 |
+
clearDraftPoints();
|
| 821 |
dispatch({ type: A.SELECT_ANNOTATION, payload: null });
|
| 822 |
}
|
| 823 |
return;
|
|
|
|
| 856 |
dispatch({ type: A.SET_MODE, payload: MODES.LASSO_DRAW });
|
| 857 |
return;
|
| 858 |
}
|
| 859 |
+
}, [
|
| 860 |
+
tool,
|
| 861 |
+
mode,
|
| 862 |
+
annotations,
|
| 863 |
+
selectedId,
|
| 864 |
+
getSvgPoint,
|
| 865 |
+
dispatch,
|
| 866 |
+
findAnnotationAtPoint,
|
| 867 |
+
interactionRef,
|
| 868 |
+
setDraftPointsImmediate,
|
| 869 |
+
clearDraftPoints,
|
| 870 |
+
]);
|
| 871 |
|
| 872 |
const handlePointerMove = useCallback((e) => {
|
| 873 |
const point = getSvgPoint(e);
|
|
|
|
| 881 |
return;
|
| 882 |
}
|
| 883 |
|
| 884 |
+
if (mode === MODES.POLYGON_DRAW) {
|
| 885 |
+
setPointerNow(point);
|
| 886 |
+
}
|
| 887 |
|
| 888 |
if (mode === MODES.DRAW_RECT && ir.pointerStart) {
|
| 889 |
setTempRect({
|
|
|
|
| 907 |
return;
|
| 908 |
}
|
| 909 |
|
| 910 |
+
if (mode === MODES.RESIZE && ir.dragTarget && ir.transformHandle) {
|
| 911 |
+
const handleIndex = Number.parseInt(String(ir.transformHandle).replace('resize-', ''), 10);
|
| 912 |
+
if (!Number.isFinite(handleIndex)) return;
|
| 913 |
+
if (!ir.historyPushed) {
|
| 914 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 915 |
+
ir.historyPushed = true;
|
| 916 |
+
}
|
| 917 |
+
ir.dragCommitted = true;
|
| 918 |
+
const resized = buildResizedRectPoints(ir.dragOriginalPoints, handleIndex, point).map((pt) => ({
|
| 919 |
+
x: clamp(pt.x, 0, imageWidth),
|
| 920 |
+
y: clamp(pt.y, 0, imageHeight),
|
| 921 |
+
}));
|
| 922 |
+
scheduleDraftPoints(resized);
|
| 923 |
+
return;
|
| 924 |
+
}
|
| 925 |
+
|
| 926 |
+
if (mode === MODES.ROTATE && ir.dragTarget && ir.pointerStart) {
|
| 927 |
+
const originalPoints = ir.dragOriginalPoints;
|
| 928 |
+
if (!Array.isArray(originalPoints) || originalPoints.length !== 4) return;
|
| 929 |
+
const center = midpoint(originalPoints[0], originalPoints[2]);
|
| 930 |
+
const startAngle = Math.atan2(ir.pointerStart.y - center.y, ir.pointerStart.x - center.x);
|
| 931 |
+
const currentAngle = Math.atan2(point.y - center.y, point.x - center.x);
|
| 932 |
+
const deltaDeg = ((currentAngle - startAngle) * 180) / Math.PI;
|
| 933 |
+
if (!ir.dragCommitted && Math.abs(deltaDeg) < 1.2) return;
|
| 934 |
+
if (!ir.historyPushed) {
|
| 935 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 936 |
+
ir.historyPushed = true;
|
| 937 |
+
}
|
| 938 |
+
ir.dragCommitted = true;
|
| 939 |
+
scheduleDraftPoints(rotatePointsAround(originalPoints, center, deltaDeg));
|
| 940 |
+
return;
|
| 941 |
+
}
|
| 942 |
+
|
| 943 |
if (mode === MODES.MOVE && ir.dragTarget && ir.pointerStart) {
|
| 944 |
const dx = point.x - ir.pointerStart.x;
|
| 945 |
const dy = point.y - ir.pointerStart.y;
|
| 946 |
if (!ir.dragCommitted && Math.hypot(dx, dy) < MOVE_THRESHOLD) return;
|
| 947 |
+
if (!ir.historyPushed) {
|
| 948 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 949 |
+
ir.historyPushed = true;
|
| 950 |
+
}
|
| 951 |
ir.dragCommitted = true;
|
| 952 |
const moved = ir.dragOriginalPoints.map((p) => ({
|
| 953 |
x: clamp(p.x + dx, 0, imageWidth),
|
| 954 |
y: clamp(p.y + dy, 0, imageHeight),
|
| 955 |
}));
|
| 956 |
+
scheduleDraftPoints(moved);
|
|
|
|
|
|
|
|
|
|
| 957 |
return;
|
| 958 |
}
|
| 959 |
|
| 960 |
if (mode === MODES.VERTEX && ir.dragTarget != null) {
|
| 961 |
const ann = annotations.find((a) => a.id === ir.dragTarget);
|
| 962 |
if (ann) {
|
| 963 |
+
if (!ir.historyPushed) {
|
| 964 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 965 |
+
ir.historyPushed = true;
|
| 966 |
+
}
|
| 967 |
+
ir.dragCommitted = true;
|
| 968 |
+
const sourcePoints = Array.isArray(draftPoints) ? draftPoints : ann.points;
|
| 969 |
+
const newPoints = sourcePoints.map((p, i) =>
|
| 970 |
i === ir.dragVertexIndex
|
| 971 |
? { x: clamp(point.x, 0, imageWidth), y: clamp(point.y, 0, imageHeight) }
|
| 972 |
: p
|
| 973 |
);
|
| 974 |
+
scheduleDraftPoints(newPoints);
|
|
|
|
|
|
|
|
|
|
| 975 |
}
|
| 976 |
return;
|
| 977 |
}
|
| 978 |
+
}, [mode, getSvgPoint, imageWidth, imageHeight, dispatch, annotations, interactionRef, draftPoints, scheduleDraftPoints]);
|
| 979 |
|
| 980 |
const handlePointerUp = useCallback(() => {
|
| 981 |
const ir = interactionRef.current;
|
|
|
|
| 1016 |
}
|
| 1017 |
|
| 1018 |
if (mode === MODES.MOVE) {
|
| 1019 |
+
const committedPoints = Array.isArray(draftPointsRef.current) ? draftPointsRef.current : draftPoints;
|
| 1020 |
+
const annotation = annotations.find((item) => item.id === ir.dragTarget);
|
| 1021 |
+
if (ir.dragCommitted && annotation && Array.isArray(committedPoints)) {
|
| 1022 |
+
commitAnnotationGeometry(annotation, committedPoints);
|
| 1023 |
+
}
|
| 1024 |
ir.dragTarget = null;
|
| 1025 |
ir.dragOriginalPoints = null;
|
| 1026 |
+
ir.pointerStart = null;
|
| 1027 |
+
ir.transformHandle = '';
|
| 1028 |
ir.dragCommitted = false;
|
| 1029 |
+
ir.historyPushed = false;
|
| 1030 |
+
clearDraftPoints();
|
| 1031 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 1032 |
return;
|
| 1033 |
}
|
| 1034 |
|
| 1035 |
if (mode === MODES.VERTEX) {
|
| 1036 |
+
const committedPoints = Array.isArray(draftPointsRef.current) ? draftPointsRef.current : draftPoints;
|
| 1037 |
+
if (ir.dragCommitted && ir.dragTarget && Array.isArray(committedPoints)) {
|
| 1038 |
+
updateAnnotationPoints(ir.dragTarget, committedPoints);
|
| 1039 |
+
}
|
| 1040 |
ir.dragTarget = null;
|
| 1041 |
ir.dragVertexIndex = -1;
|
| 1042 |
+
ir.pointerStart = null;
|
| 1043 |
+
ir.transformHandle = '';
|
| 1044 |
+
ir.dragCommitted = false;
|
| 1045 |
+
ir.historyPushed = false;
|
| 1046 |
+
clearDraftPoints();
|
| 1047 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 1048 |
return;
|
| 1049 |
}
|
| 1050 |
+
|
| 1051 |
+
if (mode === MODES.RESIZE || mode === MODES.ROTATE) {
|
| 1052 |
+
const committedPoints = Array.isArray(draftPointsRef.current) ? draftPointsRef.current : draftPoints;
|
| 1053 |
+
const annotation = annotations.find((item) => item.id === ir.dragTarget);
|
| 1054 |
+
if (ir.dragCommitted && annotation && Array.isArray(committedPoints)) {
|
| 1055 |
+
commitAnnotationGeometry(annotation, committedPoints);
|
| 1056 |
+
}
|
| 1057 |
+
ir.dragTarget = null;
|
| 1058 |
+
ir.dragOriginalPoints = null;
|
| 1059 |
+
ir.pointerStart = null;
|
| 1060 |
+
ir.transformHandle = '';
|
| 1061 |
+
ir.dragCommitted = false;
|
| 1062 |
+
ir.historyPushed = false;
|
| 1063 |
+
clearDraftPoints();
|
| 1064 |
+
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 1065 |
+
return;
|
| 1066 |
+
}
|
| 1067 |
+
}, [mode, tempRect, createAnnotation, dispatch, interactionRef, draftPoints, annotations, updateAnnotationPoints, clearDraftPoints, commitAnnotationGeometry]);
|
| 1068 |
|
| 1069 |
const finishPolygon = useCallback(() => {
|
| 1070 |
const ir = interactionRef.current;
|
|
|
|
| 1087 |
interactionRef.current.tempPoints = [];
|
| 1088 |
setTempPoints([]);
|
| 1089 |
setTempRect(null);
|
| 1090 |
+
clearDraftPoints();
|
| 1091 |
+
interactionRef.current.dragTarget = null;
|
| 1092 |
+
interactionRef.current.dragOriginalPoints = null;
|
| 1093 |
+
interactionRef.current.dragVertexIndex = -1;
|
| 1094 |
+
interactionRef.current.pointerStart = null;
|
| 1095 |
+
interactionRef.current.transformHandle = '';
|
| 1096 |
+
interactionRef.current.dragCommitted = false;
|
| 1097 |
+
interactionRef.current.historyPushed = false;
|
| 1098 |
dispatch({ type: A.SET_MODE, payload: MODES.IDLE });
|
| 1099 |
}
|
| 1100 |
}
|
| 1101 |
window.addEventListener('keydown', handleKey);
|
| 1102 |
return () => window.removeEventListener('keydown', handleKey);
|
| 1103 |
+
}, [mode, finishPolygon, dispatch, interactionRef, clearDraftPoints]);
|
|
|
|
|
|
|
| 1104 |
|
| 1105 |
if (!imageDataUrl) {
|
| 1106 |
return (
|
|
|
|
| 1116 |
const svgW = imageWidth * zoom;
|
| 1117 |
const svgH = imageHeight * zoom;
|
| 1118 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1119 |
return (
|
| 1120 |
<div className="viewer-panel" style={{ display: 'flex', flexDirection: 'column' }}>
|
| 1121 |
<div
|
|
|
|
| 1154 |
</defs>
|
| 1155 |
<image href={imageDataUrl} x="0" y="0" width={imageWidth} height={imageHeight} />
|
| 1156 |
|
| 1157 |
+
<g id="overlayLegend" transform={`translate(${12 / zoom}, ${12 / zoom})`}>
|
| 1158 |
+
<rect
|
| 1159 |
+
x="0"
|
| 1160 |
+
y="0"
|
| 1161 |
+
width={170 / zoom}
|
| 1162 |
+
height={58 / zoom}
|
| 1163 |
+
rx={8 / zoom}
|
| 1164 |
+
fill="rgba(15,23,42,0.78)"
|
| 1165 |
+
stroke="rgba(255,255,255,0.22)"
|
| 1166 |
+
strokeWidth={1 / zoom}
|
| 1167 |
+
/>
|
| 1168 |
+
<text x={10 / zoom} y={16 / zoom} fill="white" fontSize={10 / zoom} fontWeight="700">
|
| 1169 |
+
Объекты на схеме
|
| 1170 |
+
</text>
|
| 1171 |
+
<text x={10 / zoom} y={31 / zoom} fill="rgba(255,255,255,0.92)" fontSize={9 / zoom}>
|
| 1172 |
+
A:* распознано автоматически
|
| 1173 |
+
</text>
|
| 1174 |
+
<text x={10 / zoom} y={45 / zoom} fill="rgba(255,255,255,0.92)" fontSize={9 / zoom}>
|
| 1175 |
+
M:* добавлено пользователем
|
| 1176 |
+
</text>
|
| 1177 |
+
</g>
|
| 1178 |
+
|
| 1179 |
{/* Annotations layer */}
|
| 1180 |
<g id="annotationsLayer">
|
| 1181 |
{sorted.map((ann) => {
|
| 1182 |
const isSelected = ann.id === selectedId;
|
| 1183 |
+
const points = isSelected && Array.isArray(draftPoints) ? draftPoints : ann.points;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1184 |
return (
|
| 1185 |
+
<AnnotationNode
|
| 1186 |
+
key={ann.id}
|
| 1187 |
+
ann={ann}
|
| 1188 |
+
points={points}
|
| 1189 |
+
isSelected={isSelected}
|
| 1190 |
+
zoom={zoom}
|
| 1191 |
+
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1192 |
);
|
| 1193 |
})}
|
| 1194 |
</g>
|
web-new/src/constants.js
CHANGED
|
@@ -1,31 +1,41 @@
|
|
| 1 |
export const ALLOWED_CATEGORIES = Object.freeze([
|
| 2 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
]);
|
| 4 |
|
| 5 |
export const CATEGORY_COLORS = Object.freeze({
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
| 11 |
other: '#94a3b8',
|
| 12 |
});
|
| 13 |
|
| 14 |
export const CATEGORY_LABELS = Object.freeze({
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
| 20 |
other: 'Другое',
|
| 21 |
});
|
| 22 |
|
| 23 |
export const CATEGORY_KEYS = Object.freeze({
|
| 24 |
-
1: '
|
| 25 |
-
2: '
|
| 26 |
-
3: 'indicator',
|
| 27 |
-
5: 'value',
|
| 28 |
-
6: 'other',
|
| 29 |
});
|
| 30 |
|
| 31 |
export const SOURCE_COLORS = Object.freeze({
|
|
@@ -57,6 +67,8 @@ export const MODES = Object.freeze({
|
|
| 57 |
LASSO_DRAW: 'lasso-draw',
|
| 58 |
MOVE: 'move',
|
| 59 |
VERTEX: 'vertex',
|
|
|
|
|
|
|
| 60 |
TRIM_CUT: 'trim-cut',
|
| 61 |
SPLIT_CUT: 'split-cut',
|
| 62 |
TRACE_PICK: 'trace-pick',
|
|
|
|
| 1 |
export const ALLOWED_CATEGORIES = Object.freeze([
|
| 2 |
+
'widget', 'static',
|
| 3 |
+
]);
|
| 4 |
+
|
| 5 |
+
export const CATEGORY_SELECT_OPTIONS = Object.freeze([
|
| 6 |
+
{ id: 'widget', label: 'Виджет', category: 'widget', detectedKind: 'widget', color: '#3158ff' },
|
| 7 |
+
{ id: 'static-shape', label: 'Шейп', category: 'static', detectedKind: 'shape', color: '#f97316' },
|
| 8 |
+
{ id: 'static-arrow', label: 'Стрелка процесса', category: 'static', detectedKind: 'arrow', color: '#ff4f87' },
|
| 9 |
+
{ id: 'static-form', label: 'Статическая форма', category: 'static', detectedKind: 'form', color: '#16a34a' },
|
| 10 |
]);
|
| 11 |
|
| 12 |
export const CATEGORY_COLORS = Object.freeze({
|
| 13 |
+
widget: '#3158ff',
|
| 14 |
+
static: '#16a34a',
|
| 15 |
+
table: '#16a34a',
|
| 16 |
+
equipment: '#16a34a',
|
| 17 |
+
indicator: '#3158ff',
|
| 18 |
+
pipe: '#16a34a',
|
| 19 |
+
value: '#3158ff',
|
| 20 |
+
text: '#16a34a',
|
| 21 |
other: '#94a3b8',
|
| 22 |
});
|
| 23 |
|
| 24 |
export const CATEGORY_LABELS = Object.freeze({
|
| 25 |
+
widget: 'Виджет',
|
| 26 |
+
static: 'Статика',
|
| 27 |
+
table: 'Статика',
|
| 28 |
+
equipment: 'Статика',
|
| 29 |
+
indicator: 'Виджет',
|
| 30 |
+
pipe: 'Статика',
|
| 31 |
+
value: 'Виджет',
|
| 32 |
+
text: 'Статика',
|
| 33 |
other: 'Другое',
|
| 34 |
});
|
| 35 |
|
| 36 |
export const CATEGORY_KEYS = Object.freeze({
|
| 37 |
+
1: 'widget',
|
| 38 |
+
2: 'static',
|
|
|
|
|
|
|
|
|
|
| 39 |
});
|
| 40 |
|
| 41 |
export const SOURCE_COLORS = Object.freeze({
|
|
|
|
| 67 |
LASSO_DRAW: 'lasso-draw',
|
| 68 |
MOVE: 'move',
|
| 69 |
VERTEX: 'vertex',
|
| 70 |
+
RESIZE: 'resize',
|
| 71 |
+
ROTATE: 'rotate',
|
| 72 |
TRIM_CUT: 'trim-cut',
|
| 73 |
SPLIT_CUT: 'split-cut',
|
| 74 |
TRACE_PICK: 'trace-pick',
|
web-new/src/hooks/useAnnotationTools.js
CHANGED
|
@@ -51,6 +51,7 @@ function buildAnnotation(points, imageWidth, imageHeight, annotations, source =
|
|
| 51 |
return {
|
| 52 |
id: uid('ann'),
|
| 53 |
number: num,
|
|
|
|
| 54 |
bindingUid: '',
|
| 55 |
type,
|
| 56 |
points: cleaned,
|
|
@@ -63,6 +64,11 @@ function buildAnnotation(points, imageWidth, imageHeight, annotations, source =
|
|
| 63 |
category: 'other',
|
| 64 |
widgetNameOverride: '',
|
| 65 |
staticShapeNameOverride: '',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
createdAt: Date.now(),
|
| 67 |
reviewed,
|
| 68 |
reviewedAt: reviewed ? Date.now() : 0,
|
|
@@ -78,7 +84,10 @@ export function useAnnotationTools() {
|
|
| 78 |
dragTarget: null,
|
| 79 |
dragOriginalPoints: null,
|
| 80 |
dragVertexIndex: -1,
|
|
|
|
|
|
|
| 81 |
dragCommitted: false,
|
|
|
|
| 82 |
tempRect: null,
|
| 83 |
tempPoints: [],
|
| 84 |
isPanning: false,
|
|
@@ -101,7 +110,7 @@ export function useAnnotationTools() {
|
|
| 101 |
|
| 102 |
const area = Math.max(1, polygonArea(ann.points));
|
| 103 |
const boundsArea = Math.max(1, bounds.width * bounds.height);
|
| 104 |
-
const inside = ann.type === 'rect'
|
| 105 |
? pointInRect(point, bounds)
|
| 106 |
: (pointInRect(point, bounds) && pointInPolygon(point, ann.points));
|
| 107 |
const edgeDist = pointToPolygonEdgeDistance(point, ann.points);
|
|
@@ -164,7 +173,16 @@ export function useAnnotationTools() {
|
|
| 164 |
}
|
| 165 |
dispatch({
|
| 166 |
type: A.UPDATE_ANNOTATION,
|
| 167 |
-
payload: {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
});
|
| 169 |
}, [dispatch, state.annotations, state.imageWidth, state.imageHeight]);
|
| 170 |
|
|
@@ -173,8 +191,30 @@ export function useAnnotationTools() {
|
|
| 173 |
if (!ann) return;
|
| 174 |
const offset = 15;
|
| 175 |
const shifted = ann.points.map((p) => ({ x: p.x + offset, y: p.y + offset }));
|
| 176 |
-
|
| 177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
|
| 179 |
const selectNext = useCallback((direction = 1) => {
|
| 180 |
if (!state.annotations.length) return;
|
|
|
|
| 51 |
return {
|
| 52 |
id: uid('ann'),
|
| 53 |
number: num,
|
| 54 |
+
displayNumber: null,
|
| 55 |
bindingUid: '',
|
| 56 |
type,
|
| 57 |
points: cleaned,
|
|
|
|
| 64 |
category: 'other',
|
| 65 |
widgetNameOverride: '',
|
| 66 |
staticShapeNameOverride: '',
|
| 67 |
+
basicShape: '',
|
| 68 |
+
svgPath: '',
|
| 69 |
+
svgWidth: 0,
|
| 70 |
+
svgHeight: 0,
|
| 71 |
+
rotation: 0,
|
| 72 |
createdAt: Date.now(),
|
| 73 |
reviewed,
|
| 74 |
reviewedAt: reviewed ? Date.now() : 0,
|
|
|
|
| 84 |
dragTarget: null,
|
| 85 |
dragOriginalPoints: null,
|
| 86 |
dragVertexIndex: -1,
|
| 87 |
+
dragOriginalRotation: 0,
|
| 88 |
+
transformHandle: '',
|
| 89 |
dragCommitted: false,
|
| 90 |
+
historyPushed: false,
|
| 91 |
tempRect: null,
|
| 92 |
tempPoints: [],
|
| 93 |
isPanning: false,
|
|
|
|
| 110 |
|
| 111 |
const area = Math.max(1, polygonArea(ann.points));
|
| 112 |
const boundsArea = Math.max(1, bounds.width * bounds.height);
|
| 113 |
+
const inside = ann.type === 'rect' && isLikelyRect(ann.points)
|
| 114 |
? pointInRect(point, bounds)
|
| 115 |
: (pointInRect(point, bounds) && pointInPolygon(point, ann.points));
|
| 116 |
const edgeDist = pointToPolygonEdgeDistance(point, ann.points);
|
|
|
|
| 173 |
}
|
| 174 |
dispatch({
|
| 175 |
type: A.UPDATE_ANNOTATION,
|
| 176 |
+
payload: {
|
| 177 |
+
id,
|
| 178 |
+
changes: {
|
| 179 |
+
points: next,
|
| 180 |
+
type,
|
| 181 |
+
rotation: type === 'rect' ? (ann.rotation || 0) : 0,
|
| 182 |
+
reviewed: true,
|
| 183 |
+
reviewedAt: Date.now(),
|
| 184 |
+
},
|
| 185 |
+
},
|
| 186 |
});
|
| 187 |
}, [dispatch, state.annotations, state.imageWidth, state.imageHeight]);
|
| 188 |
|
|
|
|
| 191 |
if (!ann) return;
|
| 192 |
const offset = 15;
|
| 193 |
const shifted = ann.points.map((p) => ({ x: p.x + offset, y: p.y + offset }));
|
| 194 |
+
const num = nextAvailableNumber(state.annotations);
|
| 195 |
+
dispatch({ type: A.PUSH_HISTORY });
|
| 196 |
+
dispatch({
|
| 197 |
+
type: A.ADD_ANNOTATION,
|
| 198 |
+
payload: {
|
| 199 |
+
...ann,
|
| 200 |
+
id: uid('ann'),
|
| 201 |
+
number: num,
|
| 202 |
+
displayNumber: null,
|
| 203 |
+
bindingUid: '',
|
| 204 |
+
source: 'manual',
|
| 205 |
+
points: shifted,
|
| 206 |
+
createdAt: Date.now(),
|
| 207 |
+
reviewed: true,
|
| 208 |
+
reviewedAt: Date.now(),
|
| 209 |
+
xmlStatus: '',
|
| 210 |
+
xmlMatched: false,
|
| 211 |
+
xmlExported: false,
|
| 212 |
+
xmlNeedsAttention: false,
|
| 213 |
+
xmlMissingVisuals: [],
|
| 214 |
+
xmlResolvedVisuals: [],
|
| 215 |
+
},
|
| 216 |
+
});
|
| 217 |
+
}, [dispatch, state.annotations, state.selectedId]);
|
| 218 |
|
| 219 |
const selectNext = useCallback((direction = 1) => {
|
| 220 |
if (!state.annotations.length) return;
|
web-new/src/store/actions.js
CHANGED
|
@@ -29,3 +29,4 @@ export const SET_MNEMO_TITLE = 'SET_MNEMO_TITLE';
|
|
| 29 |
export const SET_LEGEND_ITEMS = 'SET_LEGEND_ITEMS';
|
| 30 |
|
| 31 |
export const IMPORT_PROJECT = 'IMPORT_PROJECT';
|
|
|
|
|
|
| 29 |
export const SET_LEGEND_ITEMS = 'SET_LEGEND_ITEMS';
|
| 30 |
|
| 31 |
export const IMPORT_PROJECT = 'IMPORT_PROJECT';
|
| 32 |
+
export const SET_ELEMENT_LIBRARY = 'SET_ELEMENT_LIBRARY';
|
web-new/src/store/reducer.js
CHANGED
|
@@ -29,6 +29,7 @@ export function createInitialState() {
|
|
| 29 |
ocrData: null,
|
| 30 |
|
| 31 |
processing: {
|
|
|
|
| 32 |
ready: false,
|
| 33 |
width: 0,
|
| 34 |
height: 0,
|
|
@@ -36,10 +37,17 @@ export function createInitialState() {
|
|
| 36 |
components: [],
|
| 37 |
counts: {},
|
| 38 |
summary: '',
|
| 39 |
-
detector: '
|
| 40 |
lastAnalyzedAt: '',
|
| 41 |
},
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
widgetExport: {
|
| 44 |
sourceXmlName: '',
|
| 45 |
sourceXmlText: '',
|
|
@@ -60,6 +68,7 @@ export function createInitialState() {
|
|
| 60 |
exportedCount: 0,
|
| 61 |
unmatchedNumbers: [],
|
| 62 |
missingVisuals: [],
|
|
|
|
| 63 |
generatedXmlText: '',
|
| 64 |
lastGeneratedAt: '',
|
| 65 |
},
|
|
@@ -71,11 +80,23 @@ function snapshotAnnotations(state) {
|
|
| 71 |
annotations: state.annotations.map((a) => ({
|
| 72 |
id: a.id, number: a.number, type: a.type,
|
| 73 |
points: a.points, source: a.source, confidence: a.confidence,
|
|
|
|
| 74 |
bindingUid: a.bindingUid,
|
| 75 |
detectedKind: a.detectedKind,
|
| 76 |
note: a.note, category: a.category, contextPath: a.contextPath,
|
| 77 |
widgetNameOverride: a.widgetNameOverride,
|
| 78 |
staticShapeNameOverride: a.staticShapeNameOverride,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
allowDuplicate: a.allowDuplicate,
|
| 80 |
reviewed: a.reviewed, reviewedAt: a.reviewedAt,
|
| 81 |
createdAt: a.createdAt,
|
|
@@ -102,10 +123,12 @@ export function reducer(state, action) {
|
|
| 102 |
ocrData: null,
|
| 103 |
processing: {
|
| 104 |
...state.processing,
|
|
|
|
| 105 |
ready: false,
|
| 106 |
components: [],
|
| 107 |
counts: {},
|
| 108 |
summary: '',
|
|
|
|
| 109 |
lastAnalyzedAt: '',
|
| 110 |
},
|
| 111 |
};
|
|
@@ -247,6 +270,17 @@ export function reducer(state, action) {
|
|
| 247 |
widgetExport: { ...state.widgetExport, legendItemsText: action.payload },
|
| 248 |
};
|
| 249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
case A.IMPORT_PROJECT: {
|
| 251 |
const p = action.payload;
|
| 252 |
return {
|
|
|
|
| 29 |
ocrData: null,
|
| 30 |
|
| 31 |
processing: {
|
| 32 |
+
pending: false,
|
| 33 |
ready: false,
|
| 34 |
width: 0,
|
| 35 |
height: 0,
|
|
|
|
| 37 |
components: [],
|
| 38 |
counts: {},
|
| 39 |
summary: '',
|
| 40 |
+
detector: '',
|
| 41 |
lastAnalyzedAt: '',
|
| 42 |
},
|
| 43 |
|
| 44 |
+
elementLibrary: {
|
| 45 |
+
statics: [],
|
| 46 |
+
widgets: [],
|
| 47 |
+
basics: [],
|
| 48 |
+
loaded: false,
|
| 49 |
+
},
|
| 50 |
+
|
| 51 |
widgetExport: {
|
| 52 |
sourceXmlName: '',
|
| 53 |
sourceXmlText: '',
|
|
|
|
| 68 |
exportedCount: 0,
|
| 69 |
unmatchedNumbers: [],
|
| 70 |
missingVisuals: [],
|
| 71 |
+
annotationResults: [],
|
| 72 |
generatedXmlText: '',
|
| 73 |
lastGeneratedAt: '',
|
| 74 |
},
|
|
|
|
| 80 |
annotations: state.annotations.map((a) => ({
|
| 81 |
id: a.id, number: a.number, type: a.type,
|
| 82 |
points: a.points, source: a.source, confidence: a.confidence,
|
| 83 |
+
displayNumber: a.displayNumber,
|
| 84 |
bindingUid: a.bindingUid,
|
| 85 |
detectedKind: a.detectedKind,
|
| 86 |
note: a.note, category: a.category, contextPath: a.contextPath,
|
| 87 |
widgetNameOverride: a.widgetNameOverride,
|
| 88 |
staticShapeNameOverride: a.staticShapeNameOverride,
|
| 89 |
+
basicShape: a.basicShape,
|
| 90 |
+
svgPath: a.svgPath,
|
| 91 |
+
svgWidth: a.svgWidth,
|
| 92 |
+
svgHeight: a.svgHeight,
|
| 93 |
+
rotation: a.rotation,
|
| 94 |
+
xmlStatus: a.xmlStatus,
|
| 95 |
+
xmlMatched: a.xmlMatched,
|
| 96 |
+
xmlExported: a.xmlExported,
|
| 97 |
+
xmlNeedsAttention: a.xmlNeedsAttention,
|
| 98 |
+
xmlMissingVisuals: a.xmlMissingVisuals,
|
| 99 |
+
xmlResolvedVisuals: a.xmlResolvedVisuals,
|
| 100 |
allowDuplicate: a.allowDuplicate,
|
| 101 |
reviewed: a.reviewed, reviewedAt: a.reviewedAt,
|
| 102 |
createdAt: a.createdAt,
|
|
|
|
| 123 |
ocrData: null,
|
| 124 |
processing: {
|
| 125 |
...state.processing,
|
| 126 |
+
pending: false,
|
| 127 |
ready: false,
|
| 128 |
components: [],
|
| 129 |
counts: {},
|
| 130 |
summary: '',
|
| 131 |
+
detector: '',
|
| 132 |
lastAnalyzedAt: '',
|
| 133 |
},
|
| 134 |
};
|
|
|
|
| 270 |
widgetExport: { ...state.widgetExport, legendItemsText: action.payload },
|
| 271 |
};
|
| 272 |
|
| 273 |
+
case A.SET_ELEMENT_LIBRARY:
|
| 274 |
+
return {
|
| 275 |
+
...state,
|
| 276 |
+
elementLibrary: {
|
| 277 |
+
statics: action.payload.statics || [],
|
| 278 |
+
widgets: action.payload.widgets || [],
|
| 279 |
+
basics: action.payload.basics || [],
|
| 280 |
+
loaded: true,
|
| 281 |
+
},
|
| 282 |
+
};
|
| 283 |
+
|
| 284 |
case A.IMPORT_PROJECT: {
|
| 285 |
const p = action.payload;
|
| 286 |
return {
|
web-new/src/utils/xmlBuilder.js
CHANGED
|
@@ -172,6 +172,46 @@ export function buildStaticShapeCell(doc, { cellId, shapeName, x, y, width, heig
|
|
| 172 |
return cell;
|
| 173 |
}
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
function indentXml(xmlStr) {
|
| 176 |
let result = '';
|
| 177 |
let indent = 0;
|
|
@@ -223,6 +263,8 @@ export function generateMnemoXml({ annotations, bindingLookup = {}, title = '',
|
|
| 223 |
const widgetName = String(ann.widgetNameOverride || ann.widget || '').trim();
|
| 224 |
const omPath = String(ann.contextPath || ann.omPath || '').trim();
|
| 225 |
const shapeName = String(ann.staticShapeNameOverride || '').trim();
|
|
|
|
|
|
|
| 226 |
|
| 227 |
const bounds = ann.bounds || {};
|
| 228 |
const x = bounds.x ?? 0;
|
|
@@ -230,6 +272,23 @@ export function generateMnemoXml({ annotations, bindingLookup = {}, title = '',
|
|
| 230 |
const w = bounds.width ?? 24;
|
| 231 |
const h = bounds.height ?? 24;
|
| 232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
if (shapeName && w > 0 && h > 0) {
|
| 234 |
root.appendChild(buildStaticShapeCell(doc, {
|
| 235 |
cellId: nextId++, shapeName, x, y, width: w, height: h,
|
|
|
|
| 172 |
return cell;
|
| 173 |
}
|
| 174 |
|
| 175 |
+
export function buildTextLabelCell(doc, { cellId, text, x, y, width, height, fontSize, align }) {
|
| 176 |
+
const fs = fontSize || Math.max(8, Math.min(24, Math.round(height * 0.65)));
|
| 177 |
+
const style = `text;html=1;strokeColor=none;fillColor=none;align=${align || 'center'};`
|
| 178 |
+
+ `verticalAlign=middle;whiteSpace=wrap;rounded=0;fontFamily=Helvetica;`
|
| 179 |
+
+ `fontSize=${fs};fontColor=#383838;`;
|
| 180 |
+
const cell = doc.createElement('mxCell');
|
| 181 |
+
setAttrs(cell, { id: cellId, value: text || '', style, parent: '1', vertex: '1' });
|
| 182 |
+
addGeometry(cell, doc, { x, y, width, height });
|
| 183 |
+
return cell;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
export function buildArrowEdgeCell(doc, { cellId, points }) {
|
| 187 |
+
if (!points || points.length < 2) return null;
|
| 188 |
+
const style = 'endArrow=classic;html=1;strokeWidth=2;strokeColor=#696969;fontColor=#383838;';
|
| 189 |
+
const cell = doc.createElement('mxCell');
|
| 190 |
+
setAttrs(cell, { id: cellId, value: '', style, parent: '1', edge: '1' });
|
| 191 |
+
const geom = doc.createElement('mxGeometry');
|
| 192 |
+
geom.setAttribute('relative', '1');
|
| 193 |
+
geom.setAttribute('as', 'geometry');
|
| 194 |
+
const src = doc.createElement('mxPoint');
|
| 195 |
+
setAttrs(src, { x: String(points[0].x), y: String(points[0].y), as: 'sourcePoint' });
|
| 196 |
+
geom.appendChild(src);
|
| 197 |
+
const tgt = doc.createElement('mxPoint');
|
| 198 |
+
const last = points[points.length - 1];
|
| 199 |
+
setAttrs(tgt, { x: String(last.x), y: String(last.y), as: 'targetPoint' });
|
| 200 |
+
geom.appendChild(tgt);
|
| 201 |
+
if (points.length > 2) {
|
| 202 |
+
const arr = doc.createElement('Array');
|
| 203 |
+
arr.setAttribute('as', 'points');
|
| 204 |
+
for (const pt of points.slice(1, -1)) {
|
| 205 |
+
const mp = doc.createElement('mxPoint');
|
| 206 |
+
setAttrs(mp, { x: String(pt.x), y: String(pt.y) });
|
| 207 |
+
arr.appendChild(mp);
|
| 208 |
+
}
|
| 209 |
+
geom.appendChild(arr);
|
| 210 |
+
}
|
| 211 |
+
cell.appendChild(geom);
|
| 212 |
+
return cell;
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
function indentXml(xmlStr) {
|
| 216 |
let result = '';
|
| 217 |
let indent = 0;
|
|
|
|
| 263 |
const widgetName = String(ann.widgetNameOverride || ann.widget || '').trim();
|
| 264 |
const omPath = String(ann.contextPath || ann.omPath || '').trim();
|
| 265 |
const shapeName = String(ann.staticShapeNameOverride || '').trim();
|
| 266 |
+
const category = String(ann.category || '').trim().toLowerCase();
|
| 267 |
+
const detectedKind = String(ann.detectedKind || '').trim().toLowerCase();
|
| 268 |
|
| 269 |
const bounds = ann.bounds || {};
|
| 270 |
const x = bounds.x ?? 0;
|
|
|
|
| 272 |
const w = bounds.width ?? 24;
|
| 273 |
const h = bounds.height ?? 24;
|
| 274 |
|
| 275 |
+
if (category === 'text' || detectedKind.startsWith('text-')) {
|
| 276 |
+
const label = String(ann.note || ann.label || '').trim();
|
| 277 |
+
if (label) {
|
| 278 |
+
root.appendChild(buildTextLabelCell(doc, {
|
| 279 |
+
cellId: nextId++, text: label, x, y, width: w, height: h,
|
| 280 |
+
align: detectedKind === 'text-equipment' || detectedKind === 'text-parameter' ? 'left' : 'center',
|
| 281 |
+
}));
|
| 282 |
+
}
|
| 283 |
+
continue;
|
| 284 |
+
}
|
| 285 |
+
|
| 286 |
+
if ((detectedKind === 'arrow' || category === 'pipe' || category === 'static') && !uid && Array.isArray(ann.points) && detectedKind === 'arrow') {
|
| 287 |
+
const edgeCell = buildArrowEdgeCell(doc, { cellId: nextId++, points: ann.points });
|
| 288 |
+
if (edgeCell) root.appendChild(edgeCell);
|
| 289 |
+
continue;
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
if (shapeName && w > 0 && h > 0) {
|
| 293 |
root.appendChild(buildStaticShapeCell(doc, {
|
| 294 |
cellId: nextId++, shapeName, x, y, width: w, height: h,
|