모델 클리핑 기능 추가
This commit is contained in:
1 parent
27b3230dba
commit
0b17a2aff6
8 files changed
+77
-16
No files matched your search
@@ -67,6 +67,7 @@
|
||||
- 화면의 면은 검토용 열린 표면 모델이다. 구조선 사이를 연결했으며 모든 두께/접합을 확정한 닫힌 체적이나 실사 렌더링은 아니다.
|
||||
- `scripts/render_block8_drawing_views.py`는 DXF 도면 영역의 선·문자를 잘라 평면도, 상부평면도, 종단면도, A-A, B-B SVG 이미지 5개와 픽셀-CAD 좌표 연결값을 만든다. 뷰어에서 현재 보기와 도면 종류를 연결하고 투명도를 조절할 수 있다.
|
||||
- A-A/B-B 이미지는 각 끝 측점의 단면 평면에 놓고, 종단면 이미지는 STA 주석과 EL 주석으로 길이·높이를 변환해 구조물 측면에 놓는다. 평면도는 DXF 좌표를 모델 좌표에 대응시키며, 상부평면도 표기는 도면 간 35m 배치 차이를 이동해 단일 모델 위에 포개고 화면 표시용 EL 108.8m에 둔다.
|
||||
- 클리핑은 X(좌우 폭), Y(표고), Z(길이/측점 방향) 축 중 하나를 골라 전체 모델 좌표 범위의 0~100% 위치에서 한쪽 표면을 잘라 표시한다. 열린 표면 모델이므로 절단면은 막지 않으며, 도면 이미지 오버레이는 참고면으로 남아 절단되지 않는다.
|
||||
- 이들은 도면 요소를 3D 화면의 기준 평면에 투영한 검토용 이미지다. 평면의 표시 높이와 종단면의 측면 이격은 보이도록 둔 시각화 위치이며 실제 부재나 설계 고도를 뜻하지 않는다. DXF 글꼴 및 일부 블록 표현은 SVG에서 단순화될 수 있다.
|
||||
- 실행: `npm run dev`. 분석 파일과 작업 로그는 화면 상단 링크에서 연다.
|
||||
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
<meta name="theme-color" content="#eff2ed">
|
||||
<meta name="description" content="도면의 중심선과 구조 단면을 연결한 광터지하차도 BLOCK8 3D 검토 모델입니다.">
|
||||
<title>광터지하차도 BLOCK8 3D 모델</title>
|
||||
<style>:root{color:#263a32;font-synthesis:none;text-rendering:optimizelegibility;background:#eff2ed;font-family:Malgun Gothic,Apple SD Gothic Neo,sans-serif}*{box-sizing:border-box}body{min-width:320px;min-height:100vh;margin:0}button,input{font:inherit}button{color:inherit;cursor:pointer;background:0 0;border:0}a{color:inherit;text-decoration:none}button:focus-visible,a:focus-visible,input:focus-visible{outline-offset:3px;outline:2px solid #bc763b}.page-shell{width:min(100% - 64px,1600px);margin:auto;padding-bottom:24px}.topbar{border-bottom:1px solid #d9e1d7;align-items:center;gap:18px;min-height:72px;display:flex}.brand{white-space:nowrap;align-items:center;gap:10px;font-size:14px;font-weight:700;display:flex}.brand-mark{color:#fff;background:#446b58;border-radius:10px;place-items:center;width:34px;height:34px;font-size:11px;display:grid}.project-chip{color:#7a897e;margin-right:auto;font-size:11px}.file-links{gap:7px;display:flex}.file-links a{color:#536d5b;white-space:nowrap;background:#fafcf8;border:1px solid #d3ddd2;border-radius:7px;padding:9px 11px;font-size:10px}.file-links a:hover,.source-links a:hover{color:#315c42;border-color:#92a994}.intro{justify-content:space-between;align-items:center;gap:18px;padding:29px 0 20px;display:flex}.kicker,.eyebrow{color:#7a8d7e;letter-spacing:.08em;font-size:10px;font-weight:700;display:block}h1{letter-spacing:-.055em;margin:8px 0;font-size:clamp(26px,3.3vw,34px)}h1 em{color:#738b79;margin-left:7px;font-size:.8em;font-style:normal;font-weight:400}.intro p{color:#7c8d80;margin:0;font-size:11px;line-height:1.7}.status-pill{color:#9b793c;white-space:nowrap;background:#f8f4e9;border:1px solid #e0d6bd;border-radius:30px;align-items:center;gap:8px;padding:9px 13px;font-size:10px;display:flex}.status-pill i{background:#b08a45;border-radius:50%;width:7px;height:7px}.metrics{background:#f9fbf7;border:1px solid #dce4d9;border-radius:11px;grid-template-columns:repeat(4,1fr);margin-bottom:13px;padding:17px 0;display:grid}.metrics article{border-right:1px solid #e3e8df;min-width:0;padding:0 18px}.metrics article:last-child{border:0}.metrics small{color:#7d8b7d;font-size:9px;display:block}.metrics strong{white-space:nowrap;margin:8px 0 5px;font-family:Georgia,serif;font-size:clamp(19px,2.3vw,26px);font-weight:400;display:block}.metrics strong.el{font-size:clamp(17px,2vw,22px)}.metrics strong i{color:#899584;font-family:sans-serif;font-size:11px;font-style:normal}.metrics p{color:#8b9687;margin:0;font-size:9px;line-height:1.55}.notice{background:#f5f0e4;border:1px solid #e6dcc7;border-radius:8px;align-items:flex-start;gap:11px;margin-bottom:15px;padding:10px 13px;display:flex}.notice b{color:#967136;white-space:nowrap;padding-top:2px;font-size:10px}.notice p{color:#8b7e62;margin:0;font-size:10px;line-height:1.65}.workspace{grid-template-columns:minmax(0,1fr) 322px;align-items:start;gap:16px;display:grid}.viewer-card,.side-card,.info-card{background:#fafcf8;border:1px solid #dbe4d7;border-radius:11px;min-width:0;overflow:hidden}.viewer-head{justify-content:space-between;align-items:center;gap:12px;padding:17px 19px 13px;display:flex}.viewer-actions{align-items:center;gap:8px;display:flex}.drawing-toggle{color:#5c765f;white-space:nowrap;border:1px solid #d4dfd2;border-radius:6px;padding:7px 10px;font-size:9px}.drawing-toggle.active{color:#385f42;background:#e9f0e7;border-color:#8aa48c}h2{letter-spacing:-.04em;margin:5px 0 0;font-size:16px}.segmented{background:#eaf0e7;border-radius:7px;padding:3px;display:flex}.segmented button{color:#7f8d7b;white-space:nowrap;border-radius:5px;padding:6px 9px;font-size:9px}.segmented button.active{color:#496c52;background:#fff;box-shadow:0 1px 4px #233c2912}.viewbar{justify-content:space-between;align-items:center;gap:10px;padding:0 17px 10px;display:flex}.views{gap:3px;display:flex}.views button{border:1px solid #0000;border-radius:5px;padding:6px 9px;font-size:9px}.views button.active{color:#426a50;background:#eef3ea;border-color:#ccdac9}.viewbar>span{color:#8b9687;white-space:nowrap;font-size:9px}.canvas-wrap{background:#f4f7f3;border-top:1px solid #dfe8da;border-bottom:1px solid #dfe8da;position:relative;overflow:hidden}.drawing-controls{background:#f7faf5;border-bottom:1px solid #e2e9dd;align-items:center;gap:14px;padding:9px 15px;display:flex}.drawing-controls label{color:#647568;white-space:nowrap;align-items:center;gap:7px;font-size:9px;display:flex}.drawing-controls select{color:#526657;background:#fff;border:1px solid #d6e0d4;border-radius:5px;max-width:180px;padding:5px 7px;font-size:9px}.drawing-controls input{accent-color:#59785e;width:95px}.drawing-controls>span{color:#879287;font-size:8px;line-height:1.5}.model-canvas{touch-action:none;cursor:grab;width:100%;height:485px;display:block}.model-canvas:active{cursor:grabbing}.model-canvas:focus-visible{outline-offset:-2px;outline:2px solid #7d9a83}.canvas-tag{color:#6c846f;pointer-events:none;background:#fcfffbd9;border:1px solid #d5e0d2;border-radius:5px;max-width:calc(100% - 28pLine truncated
|
||||
<style>:root{color:#263a32;font-synthesis:none;text-rendering:optimizelegibility;background:#eff2ed;font-family:Malgun Gothic,Apple SD Gothic Neo,sans-serif}*{box-sizing:border-box}body{min-width:320px;min-height:100vh;margin:0}button,input{font:inherit}button{color:inherit;cursor:pointer;background:0 0;border:0}a{color:inherit;text-decoration:none}button:focus-visible,a:focus-visible,input:focus-visible{outline-offset:3px;outline:2px solid #bc763b}.page-shell{width:min(100% - 64px,1600px);margin:auto;padding-bottom:24px}.topbar{border-bottom:1px solid #d9e1d7;align-items:center;gap:18px;min-height:72px;display:flex}.brand{white-space:nowrap;align-items:center;gap:10px;font-size:14px;font-weight:700;display:flex}.brand-mark{color:#fff;background:#446b58;border-radius:10px;place-items:center;width:34px;height:34px;font-size:11px;display:grid}.project-chip{color:#7a897e;margin-right:auto;font-size:11px}.file-links{gap:7px;display:flex}.file-links a{color:#536d5b;white-space:nowrap;background:#fafcf8;border:1px solid #d3ddd2;border-radius:7px;padding:9px 11px;font-size:10px}.file-links a:hover,.source-links a:hover{color:#315c42;border-color:#92a994}.intro{justify-content:space-between;align-items:center;gap:18px;padding:29px 0 20px;display:flex}.kicker,.eyebrow{color:#7a8d7e;letter-spacing:.08em;font-size:10px;font-weight:700;display:block}h1{letter-spacing:-.055em;margin:8px 0;font-size:clamp(26px,3.3vw,34px)}h1 em{color:#738b79;margin-left:7px;font-size:.8em;font-style:normal;font-weight:400}.intro p{color:#7c8d80;margin:0;font-size:11px;line-height:1.7}.status-pill{color:#9b793c;white-space:nowrap;background:#f8f4e9;border:1px solid #e0d6bd;border-radius:30px;align-items:center;gap:8px;padding:9px 13px;font-size:10px;display:flex}.status-pill i{background:#b08a45;border-radius:50%;width:7px;height:7px}.metrics{background:#f9fbf7;border:1px solid #dce4d9;border-radius:11px;grid-template-columns:repeat(4,1fr);margin-bottom:13px;padding:17px 0;display:grid}.metrics article{border-right:1px solid #e3e8df;min-width:0;padding:0 18px}.metrics article:last-child{border:0}.metrics small{color:#7d8b7d;font-size:9px;display:block}.metrics strong{white-space:nowrap;margin:8px 0 5px;font-family:Georgia,serif;font-size:clamp(19px,2.3vw,26px);font-weight:400;display:block}.metrics strong.el{font-size:clamp(17px,2vw,22px)}.metrics strong i{color:#899584;font-family:sans-serif;font-size:11px;font-style:normal}.metrics p{color:#8b9687;margin:0;font-size:9px;line-height:1.55}.notice{background:#f5f0e4;border:1px solid #e6dcc7;border-radius:8px;align-items:flex-start;gap:11px;margin-bottom:15px;padding:10px 13px;display:flex}.notice b{color:#967136;white-space:nowrap;padding-top:2px;font-size:10px}.notice p{color:#8b7e62;margin:0;font-size:10px;line-height:1.65}.workspace{grid-template-columns:minmax(0,1fr) 322px;align-items:start;gap:16px;display:grid}.viewer-card,.side-card,.info-card{background:#fafcf8;border:1px solid #dbe4d7;border-radius:11px;min-width:0;overflow:hidden}.viewer-head{justify-content:space-between;align-items:center;gap:12px;padding:17px 19px 13px;display:flex}.viewer-actions{align-items:center;gap:8px;display:flex}.drawing-toggle{color:#5c765f;white-space:nowrap;border:1px solid #d4dfd2;border-radius:6px;padding:7px 10px;font-size:9px}.drawing-toggle.active{color:#385f42;background:#e9f0e7;border-color:#8aa48c}h2{letter-spacing:-.04em;margin:5px 0 0;font-size:16px}.segmented{background:#eaf0e7;border-radius:7px;padding:3px;display:flex}.segmented button{color:#7f8d7b;white-space:nowrap;border-radius:5px;padding:6px 9px;font-size:9px}.segmented button.active{color:#496c52;background:#fff;box-shadow:0 1px 4px #233c2912}.viewbar{justify-content:space-between;align-items:center;gap:10px;padding:0 17px 10px;display:flex}.views{gap:3px;display:flex}.views button{border:1px solid #0000;border-radius:5px;padding:6px 9px;font-size:9px}.views button.active{color:#426a50;background:#eef3ea;border-color:#ccdac9}.viewbar>span{color:#8b9687;white-space:nowrap;font-size:9px}.canvas-wrap{background:#f4f7f3;border-top:1px solid #dfe8da;border-bottom:1px solid #dfe8da;position:relative;overflow:hidden}.drawing-controls{background:#f7faf5;border-bottom:1px solid #e2e9dd;align-items:center;gap:14px;padding:9px 15px;display:flex}.drawing-controls label{color:#647568;white-space:nowrap;align-items:center;gap:7px;font-size:9px;display:flex}.drawing-controls select{color:#526657;background:#fff;border:1px solid #d6e0d4;border-radius:5px;max-width:180px;padding:5px 7px;font-size:9px}.drawing-controls input{accent-color:#59785e;width:95px}.drawing-controls>span{color:#879287;font-size:8px;line-height:1.5}.clip-controls{background:#f4f8f1;border-bottom:1px solid #e2e9dd;flex-wrap:wrap;align-items:center;gap:9px 14px;padding:10px 15px;display:flex}.clip-controls label{color:#526b58;white-space:nowrap;align-items:center;gap:7px;font-size:9px;display:flex}.clip-controls select{color:#526657;background:#fff;border:1px solid #d2dfd0Line truncated
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script>window.BLOCK8_DRAWING_IMAGES={"plan": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAwIiBoZWlnaHQ9IjExNjAiIHZpZXdCb3g9IjAgMCAxNDAwIDExNjAiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0i7Y+J66m064+EIOybkOuzuCBEWEYg7JiB7JetIj4KPHRpdGxlPu2PieuptOuPhCDCtyDsm5Drs7ggRFhGIOuyoe2EsCDsuqHsspg8L3RpdGxlPgo8Zz48cGF0aCBkPSJNMTE1OC41NSwzMDIuOTYgTDExNjMuMzMsMTExNC45NSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNDM4YjllIiBzdHJva2Utd2lkdGg9IjEuMjUiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMzY0LjEzLDMwMi45NiBMMzU5LjM1LDExMTQuOTUiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzQzOGI5ZSIgc3Ryb2tlLXdpZHRoPSIxLjI1IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTQ2MS4wOCw3NjkuNDcgTDQ2MC42OSw4NTcuOTEiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNNDYwLjY5LDg1Ny45MSBMNDYwLjY1LDg2NS45MSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik00NjEuNjEsNjQ5LjQ3IEw0NjIuMDAsNTYxLjAzIiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTQ2Mi4wMCw1NjEuMDMgTDQ2Mi4wMyw1NTMuMDMiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTE5OS4xNiwzMzguNzIgTDEyNDEuMTYsMzM4LjQ4IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTExOTguOTUsMzAyLjcyIEwxMjQwLjk1LDMwMi40OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0xMjM5LjE2LDMzOC40OSBMMTIzOC45NSwzMDIuNDkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMS4yMiw2ODguNzIgTDEyNDMuMjIsNjg4LjQ3IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTExOTkuMTYsMzM4LjcyIEwxMjQxLjE2LDMzOC40OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0xMjQxLjIyLDY4OC40OCBMMTIzOS4xNiwzMzguNDkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMS40Niw3MjguNzIgTDEyNDMuNDUsNzI4LjQ3IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTEyMDEuMjIsNjg4LjcyIEwxMjQzLjIyLDY4OC40NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0xMjQxLjQ1LDcyOC40OCBMMTI0MS4yMiw2ODguNDgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMy41MSwxMDc4LjcxIEwxMjQ1LjUxLDEwNzguNDYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMS40Niw3MjguNzIgTDEyNDMuNDUsNzI4LjQ3IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTEyNDMuNTEsMTA3OC40OCBMMTI0MS40NSw3MjguNDgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMy43MywxMTE0LjcxIEwxMjQ1LjczLDExMTQuNDYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTIwMy41MSwxMDc4LjcxIEwxMjQ1LjUxLDEwNzguNDYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMTI0My43MywxMTE0LjQ4IEwxMjQzLjUxLDEwNzguNDgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMzIzLjUyLDMzOC43MiBMMjgxLjUyLDMzOC40OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMjMuNzMsMzAyLjcyIEwyODEuNzMsMzAyLjQ4IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTI4My41MiwzMzguNDkgTDI4My43MywzMDIuNDkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMzIxLjQ2LDY4OC43MiBMMjc5LjQ2LDY4OC40NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMjMuNTIsMzM4LjcyIEwyODEuNTIsMzM4LjQ4IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTI4MS40Niw2ODguNDggTDI4My41MiwzMzguNDkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMzIxLjIzLDcyOC43MiBMMjc5LjIzLDcyOC40NyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZDI1MjQ1IiBzdHJva2Utd2lkdGg9IjAuOCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMjEuNDYsNjg4LjcyIEwyNzkuNDYsNjg4LjQ3IiBmaWxsPSJub25lIiBzdHJva2U9IiNkMjUyNDUiIHN0cm9rZS13aWR0aD0iMC44IiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTI4MS4yMyw3MjguNDggTDI4MS40Niw2ODguNDgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2QyNTI0NSIgc3Ryb2tlLXdpZHRoPSIwLjgiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48cGF0aCBkPSJNMzE5LjE3LDEwNzguNzEgTDI3Ny4xNywxMDc4LjQ2IiBmaWxsPSJub25lIiBzdHJvLine truncated
|
||||
<script>var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t,t.exports),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.for(`react.view_transition`),m=Symbol.iterator;function h(e){return typeof e!=`object`||!e?null:(e=m&&e[m]||e[`@@iterator`],typeof e==`function`?e:null)}var g={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,v={};function y(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||g}y.prototype.isReactComponent={},y.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},y.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function b(){}b.prototype=y.prototype;function ee(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||g}var x=ee.prototype=new b;x.constructor=ee,_(x,y.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},te=Object.prototype.hasOwnProperty;function T(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function ne(e,t){return T(e.type,t,e.props)}function re(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ie(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ae=/\/+/g;function oe(e,t){return typeof e==`object`&&e&&e.key!=null?ie(``+e.key):t.toString(36)}function se(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ce(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ce(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+oe(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ae,`$&/`)+`/`),ce(o,r,i,``,function(e){return e})):o!=null&&(re(o)&&(o=ne(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ae,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u<e.length;u++)a=e[u],s=l+oe(a,u),c+=ce(a,r,i,s,o);else if(u=h(e),typeof u==`function`)for(e=u.call(e),u=0;!(a=e.next()).done;)a=a.value,s=l+oe(a,u++),c+=ce(a,r,i,s,o);else if(s===`object`){if(typeof e.then==`function`)return ce(se(e),r,i,a,o);throw r=String(e),Error(`Objects are not valid as a React child (found: `+(r===`[object Object]`?`object with keys {`+Object.keys(e).join(`, `)+`}`:r)+`). If you meant to render a collection of children, use an array instead.`)}return c}function le(e,t,n){if(e==null)return e;var r=[],i=0;return ce(e,r,``,``,function(e){return t.call(n,e,i++)}),r}function ue(e){if(e._status===-1){var t=e._result,n=t();n.then(function(t){(e._status===0||e._status===-1)&&(e._status=1,e._result=t,n.status===void 0&&(n.status=`fulfilled`,n.value=t))},function(t){(e._status===0||e._status===-1)&&(e._status=2,e._result=t,n.status===void 0&&(n.status=`rejected`,n.reason=t))}),e._status===-1&Line truncated
|
||||
<script>var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t,t.exports),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.for(`react.view_transition`),m=Symbol.iterator;function h(e){return typeof e!=`object`||!e?null:(e=m&&e[m]||e[`@@iterator`],typeof e==`function`?e:null)}var g={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,v={};function y(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||g}y.prototype.isReactComponent={},y.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},y.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function b(){}b.prototype=y.prototype;function ee(e,t,n){this.props=e,this.context=t,this.refs=v,this.updater=n||g}var x=ee.prototype=new b;x.constructor=ee,_(x,y.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function te(){}var C={H:null,A:null,T:null,S:null},ne=Object.prototype.hasOwnProperty;function w(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function re(e,t){return w(e.type,t,e.props)}function ie(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function ae(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var T=/\/+/g;function E(e,t){return typeof e==`object`&&e&&e.key!=null?ae(``+e.key):t.toString(36)}function oe(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(te,te):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function se(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,se(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+E(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(T,`$&/`)+`/`),se(o,r,i,``,function(e){return e})):o!=null&&(ie(o)&&(o=re(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(T,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u<e.length;u++)a=e[u],s=l+E(a,u),c+=se(a,r,i,s,o);else if(u=h(e),typeof u==`function`)for(e=u.call(e),u=0;!(a=e.next()).done;)a=a.value,s=l+E(a,u++),c+=se(a,r,i,s,o);else if(s===`object`){if(typeof e.then==`function`)return se(oe(e),r,i,a,o);throw r=String(e),Error(`Objects are not valid as a React child (found: `+(r===`[object Object]`?`object with keys {`+Object.keys(e).join(`, `)+`}`:r)+`). If you meant to render a collection of children, use an array instead.`)}return c}function ce(e,t,n){if(e==null)return e;var r=[],i=0;return se(e,r,``,``,function(e){return t.call(n,e,i++)}),r}function le(e){if(e._status===-1){var t=e._result,n=t();n.then(function(t){(e._status===0||e._status===-1)&&(e._status=1,e._result=t,n.status===void 0&&(n.status=`fulfilled`,n.value=t))},function(t){(e._status===0||e._status===-1)&&(e._status=2,e._result=t,n.status===void 0&&(n.status=`rejected`,n.reason=t))}),e._status===-1&&(e.Line truncated
|
||||
at`)?` (<anonymous>)`:-1<e.stack.indexOf(`@`)?`@unknown:0:0`:``}return`
|
||||
`+Re+e+ze}var Ve=!1;function He(e,t){if(!e||Ve)return``;Ve=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var n=function(){throw Error()};if(Object.defineProperty(n.prototype,"props",{set:function(){throw Error()}}),typeof Reflect==`object`&&Reflect.construct){try{Reflect.construct(n,[])}catch(e){var r=e}Reflect.construct(e,[],n)}else{try{n.call()}catch(e){r=e}n=!1;try{var i=Object.getOwnPropertyDescriptor(e.prototype,`props`);Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),n=!0,new e}finally{n&&(i===void 0?delete e.prototype.props:Object.defineProperty(e.prototype,"props",i))}}}else{try{throw Error()}catch(e){r=e}(n=e())&&typeof n.catch==`function`&&n.catch(function(){})}}catch(e){if(e&&r&&typeof e.stack==`string`)return[e.stack,r.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName=`DetermineComponentFrameRoot`;var i=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,`name`);i&&i.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:`DetermineComponentFrameRoot`});var a=r.DetermineComponentFrameRoot(),o=a[0],s=a[1];if(o&&s){var c=o.split(`
|
||||
`+Le+e+Re}var Be=!1;function Ve(e,t){if(!e||Be)return``;Be=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var n=function(){throw Error()};if(Object.defineProperty(n.prototype,"props",{set:function(){throw Error()}}),typeof Reflect==`object`&&Reflect.construct){try{Reflect.construct(n,[])}catch(e){var r=e}Reflect.construct(e,[],n)}else{try{n.call()}catch(e){r=e}n=!1;try{var i=Object.getOwnPropertyDescriptor(e.prototype,`props`);Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),n=!0,new e}finally{n&&(i===void 0?delete e.prototype.props:Object.defineProperty(e.prototype,"props",i))}}}else{try{throw Error()}catch(e){r=e}(n=e())&&typeof n.catch==`function`&&n.catch(function(){})}}catch(e){if(e&&r&&typeof e.stack==`string`)return[e.stack,r.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName=`DetermineComponentFrameRoot`;var i=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,`name`);i&&i.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:`DetermineComponentFrameRoot`});var a=r.DetermineComponentFrameRoot(),o=a[0],s=a[1];if(o&&s){var c=o.split(`
|
||||
`),l=s.split(`
|
||||
`);for(i=r=0;r<c.length&&!c[r].includes(`DetermineComponentFrameRoot`);)r++;for(;i<l.length&&!l[i].includes(`DetermineComponentFrameRoot`);)i++;if(r===c.length||i===l.length)for(r=c.length-1,i=l.length-1;1<=r&&0<=i&&c[r]!==l[i];)i--;for(;1<=r&&0<=i;r--,i--)if(c[r]!==l[i]){if(r!==1||i!==1)do if(r--,i--,0>i||c[r]!==l[i]){var u=`
|
||||
`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(`<anonymous>`)&&(u=u.replace(`<anonymous>`,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{Ve=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?Be(n):``}function Ue(e,t){switch(e.tag){case 26:case 27:case 5:return Be(e.type);case 16:return Be(`Lazy`);case 13:return e.child!==t&&t!==null?Be(`Suspense Fallback`):Be(`Suspense`);case 19:return Be(`SuspenseList`);case 0:case 15:return He(e.type,!1);case 11:return He(e.type.render,!1);case 1:return He(e.type,!0);case 31:return Be(`Activity`);case 30:return Be(`ViewTransition`);default:return``}}function We(e){try{var t=``,n=null;do t+=Ue(e,n),n=e,e=e.return;while(e);return t}catch(e){return`
|
||||
`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(`<anonymous>`)&&(u=u.replace(`<anonymous>`,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{Be=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ze(n):``}function He(e,t){switch(e.tag){case 26:case 27:case 5:return ze(e.type);case 16:return ze(`Lazy`);case 13:return e.child!==t&&t!==null?ze(`Suspense Fallback`):ze(`Suspense`);case 19:return ze(`SuspenseList`);case 0:case 15:return Ve(e.type,!1);case 11:return Ve(e.type.render,!1);case 1:return Ve(e.type,!0);case 31:return ze(`Activity`);case 30:return ze(`ViewTransition`);default:return``}}function Ue(e){try{var t=``,n=null;do t+=He(e,n),n=e,e=e.return;while(e);return t}catch(e){return`
|
||||
Error generating stack: `+e.message+`
|
||||
`+e.stack}}var Ge=Object.prototype.hasOwnProperty,Ke=t.unstable_scheduleCallback,qe=t.unstable_cancelCallback,Je=t.unstable_shouldYield,Ye=t.unstable_requestPaint,Xe=t.unstable_now,Ze=t.unstable_getCurrentPriorityLevel,Qe=t.unstable_ImmediatePriority,$e=t.unstable_UserBlockingPriority,et=t.unstable_NormalPriority,tt=t.unstable_LowPriority,nt=t.unstable_IdlePriority,rt=t.log,it=t.unstable_setDisableYieldValue,at=null,ot=null;function st(e){if(typeof rt==`function`&&it(e),ot&&typeof ot.setStrictMode==`function`)try{ot.setStrictMode(at,e)}catch{}}var ct=Math.clz32?Math.clz32:dt,lt=Math.log,ut=Math.LN2;function dt(e){return e>>>=0,e===0?32:31-(lt(e)/ut|0)|0}var ft=256,pt=262144,mt=4194304;function ht(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function gt(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=ht(n))):i=ht(o):i=ht(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=ht(n))):i=ht(o)):i=ht(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function _t(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function vt(e,t){t&8&&(t|=t&32);var n=e.entangledLanes;if(n!==0)for(e=e.entanglements,n&=t;0<n;){var r=31-ct(n),i=1<<r;t|=e[r],n&=~i}return t}function yt(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function bt(){var e=mt;return mt<<=1,!(mt&62914560)&&(mt=4194304),e}function xt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function St(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ct(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0<n;){var u=31-ct(n),d=1<<u;s[u]=0,c[u]=-1;var f=l[u];if(f!==null)for(l[u]=null,u=0;u<f.length;u++){var p=f[u];p!==null&&(p.lane&=-536870913)}n&=~d}r!==0&&wt(e,r,0),a!==0&&i===0&&e.tag!==0&&(e.suspendedLanes|=a&~(o&~t))}function wt(e,t,n){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-ct(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|n&261930}function Tt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-ct(n),i=1<<r;i&t|e[r]&t&&(e[r]|=t),n&=~i}}function Et(e,t){var n=t&-t;return n=n&42?1:Dt(n),(n&(e.suspendedLanes|t))===0?n:0}function Dt(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function Ot(e){return e&=-e,2<e?8<e?e&134217727?32:268435456:8:2}function kt(){var e=D.p;return e===0?(e=window.event,e===void 0?32:Ch(e.type)):e}function At(e,t){var n=D.p;try{return D.p=e,t()}finally{D.p=n}}var jt=Math.random().toString(36).slice(2),Mt=`__reactFiber$`+jt,Nt=`__reactProps$`+jt,Pt=`__reactContainer$`+jt,Ft=`__reactEvents$`+jt,It=`__reactListeners$`+jt,Lt=`__reactHandles$`+jt,Rt=`__reactResources$`+jt,zt=`__reactMarker$`+jt,Bt=`__reactLoad$`+jt;function Vt(e){delete e[Mt],delete e[Nt],delete e[It],delete e[Lt]}function Ht(e){var t;if(t=e[Mt])return t;for(var n=e.parentNode;n;){if(t=n[Pt]||n[Mt]){if(n=t.alternate,t.child!==null||n!==null&&n.child!==null)for(e=fm(e);e!==null;){if(n=e[Mt])return n;e=fm(e)}return t}e=n,n=e.parentNode}return null}function Ut(e){if(e=e[Mt]||e[Pt]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Wt(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(i(33))}function Gt(e){var t=e[Rt];return t||=e[Rt]={hoistableStyles:new Map,hoistableScripts:new Map},t}function Kt(e){e[zt]=!0}function qt(e){e[Bt]=void 0}var Jt=new Set,Yt={};function Xt(e,t){Zt(e,t),Zt(e+`Capture`,t)}function Zt(e,t){for(Yt[e]=t,e=0;e<t.leLine truncated
|
||||
`).replace(Qf,``)}function ep(e,t){return t=$f(t),$f(e)===t}function $(e,t,n,r,a,o){switch(n){case`children`:if(typeof r==`string`)t===`body`||t===`textarea`&&r===``||bn(e,r);else if(typeof r==`number`||typeof r==`bigint`)t!==`body`&&bn(e,``+r);else return;break;case`className`:an(e,`class`,r);break;case`tabIndex`:an(e,`tabindex`,r);break;case`dir`:case`role`:case`viewBox`:case`width`:case`height`:an(e,n,r);break;case`style`:Cn(e,r,o);return;case`data`:if(t!==`object`){an(e,`data`,r);break}case`src`:case`href`:if(r===``&&(t!==`a`||n!==`href`)||r==null||typeof r==`function`||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=Dn(r),e.setAttribute(n,r);break;case`action`:case`formAction`:if(typeof r==`function`){e.setAttribute(n,`javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')`);break}if(typeof o==`function`&&(n===`formAction`?(t!==`input`&&$(e,t,`name`,a.name,a,null),$(e,t,`formEncType`,a.formEncType,a,null),$(e,t,`formMethod`,a.formMethod,a,null),$(e,t,`formTarget`,a.formTarget,a,null)):($(e,t,`encType`,a.encType,a,null),$(e,t,`method`,a.method,a,null),$(e,t,`target`,a.target,a,null))),r==null||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=Dn(r),e.setAttribute(n,r);break;case`onClick`:r!=null&&(e.onclick=On);return;case`onScroll`:r!=null&&Q(`scroll`,e);return;case`onScrollEnd`:r!=null&&Q(`scrollend`,e);return;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));o?.__html!==n&&(e.innerHTML=n)}}break;case`multiple`:e.multiple=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`muted`:e.muted=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`defaultValue`:case`defaultChecked`:case`innerHTML`:case`ref`:break;case`autoFocus`:break;case`xlinkHref`:if(r==null||typeof r==`function`||typeof r==`boolean`||typeof r==`symbol`){e.removeAttribute(`xlink:href`);break}n=Dn(r),e.setAttributeNS(`http://www.w3.org/1999/xlink`,`xlink:href`,n);break;case`contentEditable`:case`spellCheck`:case`draggable`:case`value`:case`autoReverse`:case`externalResourcesRequired`:case`focusable`:case`preserveAlpha`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`inert`:case`allowFullScreen`:case`async`:case`autoPlay`:case`controls`:case`credentialless`:case`default`:case`defer`:case`disabled`:case`disablePictureInPicture`:case`disableRemotePlayback`:case`formNoValidate`:case`hidden`:case`loop`:case`noModule`:case`noValidate`:case`open`:case`playsInline`:case`readOnly`:case`required`:case`reversed`:case`scoped`:case`seamless`:case`itemScope`:r&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``):e.removeAttribute(n);break;case`capture`:case`download`:!0===r?e.setAttribute(n,``):!1!==r&&r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`cols`:case`rows`:case`size`:case`span`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case`rowSpan`:case`start`:r==null||typeof r==`function`||typeof r==`symbol`||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case`popover`:Q(`beforetoggle`,e),Q(`toggle`,e),rn(e,`popover`,r);break;case`xlinkActuate`:on(e,`http://www.w3.org/1999/xlink`,`xlink:actuate`,r);break;case`xlinkArcrole`:on(e,`http://www.w3.org/1999/xlink`,`xlink:arcrole`,r);break;case`xlinkRole`:on(e,`http://www.w3.org/1999/xlink`,`xlink:role`,r);break;case`xlinkShow`:on(e,`http://www.w3.org/1999/xlink`,`xlink:show`,r);break;case`xlinkTitle`:on(e,`http://www.w3.org/1999/xlink`,`xlink:title`,r);break;case`xlinkType`:on(e,`http://www.w3.org/1999/xlink`,`xlink:type`,r);break;case`xmlBase`:on(e,`http://www.w3.org/XML/1998/namespace`,`xml:base`,r);break;case`xmlLang`:on(e,`http://www.w3.org/XML/1998/namespace`,`xml:lang`,r);break;case`xmlSpace`:on(e,`http://www.w3.org/XML/1998/namespace`,`xml:space`,r);break;case`is`:rn(e,`is`,r);break;case`innerText`:case`textContent`:return;default:if(!(2<n.length)||n[0]!==`o`&&n[0]!==`O`||n[1]!==`n`&&n[1]!==`N`)n=Tn.get(n)||n,rn(e,n,r);else return}k=!0}function tp(e,t,n,r,a,o){switch(n){case`style`:Cn(e,r,o);return;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));o?.__html!==n&&(e.innerHTML=n)}}break;case`children`:if(typeof r==`string`)bn(e,r);else if(typeof r==`number`||typeof r==`bigint`)bn(e,``+r);else return;break;case`onScroll`:r!=null&&Q(`scroll`,e);return;case`onScrollEnd`:r!=null&&Q(`scrollend`,e);return;case`onClick`:r!=null&&(e.onclick=On);return;case`suppressContentLine truncated
|
||||
`+e.stack}}var We=Object.prototype.hasOwnProperty,Ge=t.unstable_scheduleCallback,Ke=t.unstable_cancelCallback,qe=t.unstable_shouldYield,Je=t.unstable_requestPaint,Ye=t.unstable_now,Xe=t.unstable_getCurrentPriorityLevel,Ze=t.unstable_ImmediatePriority,Qe=t.unstable_UserBlockingPriority,$e=t.unstable_NormalPriority,et=t.unstable_LowPriority,tt=t.unstable_IdlePriority,nt=t.log,rt=t.unstable_setDisableYieldValue,it=null,at=null;function ot(e){if(typeof nt==`function`&&rt(e),at&&typeof at.setStrictMode==`function`)try{at.setStrictMode(it,e)}catch{}}var st=Math.clz32?Math.clz32:ut,ct=Math.log,lt=Math.LN2;function ut(e){return e>>>=0,e===0?32:31-(ct(e)/lt|0)|0}var dt=256,ft=262144,pt=4194304;function mt(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function ht(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=mt(n))):i=mt(o):i=mt(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=mt(n))):i=mt(o)):i=mt(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function gt(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function _t(e,t){t&8&&(t|=t&32);var n=e.entangledLanes;if(n!==0)for(e=e.entanglements,n&=t;0<n;){var r=31-st(n),i=1<<r;t|=e[r],n&=~i}return t}function vt(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function yt(){var e=pt;return pt<<=1,!(pt&62914560)&&(pt=4194304),e}function bt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function xt(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function St(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0<n;){var u=31-st(n),d=1<<u;s[u]=0,c[u]=-1;var f=l[u];if(f!==null)for(l[u]=null,u=0;u<f.length;u++){var p=f[u];p!==null&&(p.lane&=-536870913)}n&=~d}r!==0&&Ct(e,r,0),a!==0&&i===0&&e.tag!==0&&(e.suspendedLanes|=a&~(o&~t))}function Ct(e,t,n){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-st(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|n&261930}function wt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-st(n),i=1<<r;i&t|e[r]&t&&(e[r]|=t),n&=~i}}function Tt(e,t){var n=t&-t;return n=n&42?1:Et(n),(n&(e.suspendedLanes|t))===0?n:0}function Et(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function Dt(e){return e&=-e,2<e?8<e?e&134217727?32:268435456:8:2}function Ot(){var e=O.p;return e===0?(e=window.event,e===void 0?32:Ch(e.type)):e}function kt(e,t){var n=O.p;try{return O.p=e,t()}finally{O.p=n}}var At=Math.random().toString(36).slice(2),jt=`__reactFiber$`+At,Mt=`__reactProps$`+At,Nt=`__reactContainer$`+At,Pt=`__reactEvents$`+At,Ft=`__reactListeners$`+At,It=`__reactHandles$`+At,Lt=`__reactResources$`+At,Rt=`__reactMarker$`+At,zt=`__reactLoad$`+At;function Bt(e){delete e[jt],delete e[Mt],delete e[Ft],delete e[It]}function Vt(e){var t;if(t=e[jt])return t;for(var n=e.parentNode;n;){if(t=n[Nt]||n[jt]){if(n=t.alternate,t.child!==null||n!==null&&n.child!==null)for(e=fm(e);e!==null;){if(n=e[jt])return n;e=fm(e)}return t}e=n,n=e.parentNode}return null}function Ht(e){if(e=e[jt]||e[Nt]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Ut(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(i(33))}function Wt(e){var t=e[Lt];return t||=e[Lt]={hoistableStyles:new Map,hoistableScripts:new Map},t}function Gt(e){e[Rt]=!0}function Kt(e){e[zt]=void 0}var qt=new Set,Jt={};function Yt(e,t){Xt(e,t),Xt(e+`Capture`,t)}function Xt(e,t){for(Jt[e]=t,e=0;e<t.leLine truncated
|
||||
`).replace(Qf,``)}function ep(e,t){return t=$f(t),$f(e)===t}function $(e,t,n,r,a,o){switch(n){case`children`:if(typeof r==`string`)t===`body`||t===`textarea`&&r===``||yn(e,r);else if(typeof r==`number`||typeof r==`bigint`)t!==`body`&&yn(e,``+r);else return;break;case`className`:rn(e,`class`,r);break;case`tabIndex`:rn(e,`tabindex`,r);break;case`dir`:case`role`:case`viewBox`:case`width`:case`height`:rn(e,n,r);break;case`style`:Sn(e,r,o);return;case`data`:if(t!==`object`){rn(e,`data`,r);break}case`src`:case`href`:if(r===``&&(t!==`a`||n!==`href`)||r==null||typeof r==`function`||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=En(r),e.setAttribute(n,r);break;case`action`:case`formAction`:if(typeof r==`function`){e.setAttribute(n,`javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')`);break}if(typeof o==`function`&&(n===`formAction`?(t!==`input`&&$(e,t,`name`,a.name,a,null),$(e,t,`formEncType`,a.formEncType,a,null),$(e,t,`formMethod`,a.formMethod,a,null),$(e,t,`formTarget`,a.formTarget,a,null)):($(e,t,`encType`,a.encType,a,null),$(e,t,`method`,a.method,a,null),$(e,t,`target`,a.target,a,null))),r==null||typeof r==`symbol`||typeof r==`boolean`){e.removeAttribute(n);break}r=En(r),e.setAttribute(n,r);break;case`onClick`:r!=null&&(e.onclick=Dn);return;case`onScroll`:r!=null&&Q(`scroll`,e);return;case`onScrollEnd`:r!=null&&Q(`scrollend`,e);return;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));o?.__html!==n&&(e.innerHTML=n)}}break;case`multiple`:e.multiple=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`muted`:e.muted=r&&typeof r!=`function`&&typeof r!=`symbol`;break;case`suppressContentEditableWarning`:case`suppressHydrationWarning`:case`defaultValue`:case`defaultChecked`:case`innerHTML`:case`ref`:break;case`autoFocus`:break;case`xlinkHref`:if(r==null||typeof r==`function`||typeof r==`boolean`||typeof r==`symbol`){e.removeAttribute(`xlink:href`);break}n=En(r),e.setAttributeNS(`http://www.w3.org/1999/xlink`,`xlink:href`,n);break;case`contentEditable`:case`spellCheck`:case`draggable`:case`value`:case`autoReverse`:case`externalResourcesRequired`:case`focusable`:case`preserveAlpha`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`inert`:case`allowFullScreen`:case`async`:case`autoPlay`:case`controls`:case`credentialless`:case`default`:case`defer`:case`disabled`:case`disablePictureInPicture`:case`disableRemotePlayback`:case`formNoValidate`:case`hidden`:case`loop`:case`noModule`:case`noValidate`:case`open`:case`playsInline`:case`readOnly`:case`required`:case`reversed`:case`scoped`:case`seamless`:case`itemScope`:r&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,``):e.removeAttribute(n);break;case`capture`:case`download`:!0===r?e.setAttribute(n,``):!1!==r&&r!=null&&typeof r!=`function`&&typeof r!=`symbol`?e.setAttribute(n,r):e.removeAttribute(n);break;case`cols`:case`rows`:case`size`:case`span`:r!=null&&typeof r!=`function`&&typeof r!=`symbol`&&!isNaN(r)&&1<=r?e.setAttribute(n,r):e.removeAttribute(n);break;case`rowSpan`:case`start`:r==null||typeof r==`function`||typeof r==`symbol`||isNaN(r)?e.removeAttribute(n):e.setAttribute(n,r);break;case`popover`:Q(`beforetoggle`,e),Q(`toggle`,e),nn(e,`popover`,r);break;case`xlinkActuate`:an(e,`http://www.w3.org/1999/xlink`,`xlink:actuate`,r);break;case`xlinkArcrole`:an(e,`http://www.w3.org/1999/xlink`,`xlink:arcrole`,r);break;case`xlinkRole`:an(e,`http://www.w3.org/1999/xlink`,`xlink:role`,r);break;case`xlinkShow`:an(e,`http://www.w3.org/1999/xlink`,`xlink:show`,r);break;case`xlinkTitle`:an(e,`http://www.w3.org/1999/xlink`,`xlink:title`,r);break;case`xlinkType`:an(e,`http://www.w3.org/1999/xlink`,`xlink:type`,r);break;case`xmlBase`:an(e,`http://www.w3.org/XML/1998/namespace`,`xml:base`,r);break;case`xmlLang`:an(e,`http://www.w3.org/XML/1998/namespace`,`xml:lang`,r);break;case`xmlSpace`:an(e,`http://www.w3.org/XML/1998/namespace`,`xml:space`,r);break;case`is`:nn(e,`is`,r);break;case`innerText`:case`textContent`:return;default:if(!(2<n.length)||n[0]!==`o`&&n[0]!==`O`||n[1]!==`n`&&n[1]!==`N`)n=wn.get(n)||n,nn(e,n,r);else return}A=!0}function tp(e,t,n,r,a,o){switch(n){case`style`:Sn(e,r,o);return;case`dangerouslySetInnerHTML`:if(r!=null){if(typeof r!=`object`||!(`__html`in r))throw Error(i(61));if(n=r.__html,n!=null){if(a.children!=null)throw Error(i(60));o?.__html!==n&&(e.innerHTML=n)}}break;case`children`:if(typeof r==`string`)yn(e,r);else if(typeof r==`number`||typeof r==`bigint`)yn(e,``+r);else return;break;case`onScroll`:r!=null&&Q(`scroll`,e);return;case`onScrollEnd`:r!=null&&Q(`scrollend`,e);return;case`onClick`:r!=null&&(e.onclick=Dn);return;case`suppressContentLine truncated
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
@@ -67,6 +67,7 @@
|
||||
- 화면의 면은 검토용 열린 표면 모델이다. 구조선 사이를 연결했으며 모든 두께/접합을 확정한 닫힌 체적이나 실사 렌더링은 아니다.
|
||||
- `scripts/render_block8_drawing_views.py`는 DXF 도면 영역의 선·문자를 잘라 평면도, 상부평면도, 종단면도, A-A, B-B SVG 이미지 5개와 픽셀-CAD 좌표 연결값을 만든다. 뷰어에서 현재 보기와 도면 종류를 연결하고 투명도를 조절할 수 있다.
|
||||
- A-A/B-B 이미지는 각 끝 측점의 단면 평면에 놓고, 종단면 이미지는 STA 주석과 EL 주석으로 길이·높이를 변환해 구조물 측면에 놓는다. 평면도는 DXF 좌표를 모델 좌표에 대응시키며, 상부평면도 표기는 도면 간 35m 배치 차이를 이동해 단일 모델 위에 포개고 화면 표시용 EL 108.8m에 둔다.
|
||||
- 클리핑은 X(좌우 폭), Y(표고), Z(길이/측점 방향) 축 중 하나를 골라 전체 모델 좌표 범위의 0~100% 위치에서 한쪽 표면을 잘라 표시한다. 열린 표면 모델이므로 절단면은 막지 않으며, 도면 이미지 오버레이는 참고면으로 남아 절단되지 않는다.
|
||||
- 이들은 도면 요소를 3D 화면의 기준 평면에 투영한 검토용 이미지다. 평면의 표시 높이와 종단면의 측면 이격은 보이도록 둔 시각화 위치이며 실제 부재나 설계 고도를 뜻하지 않는다. DXF 글꼴 및 일부 블록 표현은 SVG에서 단순화될 수 있다.
|
||||
- 실행: `npm run dev`. 분석 파일과 작업 로그는 화면 상단 링크에서 연다.
|
||||
|
||||
|
||||
@@ -44,3 +44,7 @@
|
||||
- CAD 픽셀좌표를 모델 좌표로 변환해 A-A/B-B 끝 단면, 종단 측면, 평면 기준면으로 투영
|
||||
- 평면도·상부평면도는 35m 도면 배치 차이를 보정해 단일 구조물에 중첩
|
||||
- 단독 HTML과 전달용 소스 묶음에 추출 이미지를 포함
|
||||
8. 모델 클리핑 기능 추가
|
||||
- X(좌우), Y(높이/EL), Z(길이/측점) 축과 절단 위치·남길 방향을 선택하는 조작부 추가
|
||||
- 표면 다각형을 절단 평면에서 보간해 내부가 보이도록 처리
|
||||
- 열린 표면 모델이므로 절단면 덮개는 만들지 않고, 도면 오버레이는 참고면으로 유지
|
||||
+21
-1
@@ -28,6 +28,10 @@ export default function App() {
|
||||
const [drawingVisible, setDrawingVisible] = useState(false)
|
||||
const [drawingMode, setDrawingMode] = useState('auto')
|
||||
const [drawingOpacity, setDrawingOpacity] = useState(0.68)
|
||||
const [clipping, setClipping] = useState(false)
|
||||
const [clipAxis, setClipAxis] = useState('x')
|
||||
const [clipPosition, setClipPosition] = useState(50)
|
||||
const [clipKeep, setClipKeep] = useState('positive')
|
||||
const [hidden, setHidden] = useState(new Set())
|
||||
const [selected, setSelected] = useState(null)
|
||||
const [tab, setTab] = useState('부재')
|
||||
@@ -105,6 +109,7 @@ export default function App() {
|
||||
<div className="viewer-actions">
|
||||
<div className="segmented"><button className={!renderMode ? 'active' : ''} onClick={() => setRenderMode(false)}>기본 모델</button><button className={renderMode ? 'active' : ''} onClick={() => setRenderMode(true)}>명암 보기</button></div>
|
||||
<button className={`drawing-toggle ${drawingVisible ? 'active' : ''}`} onClick={() => setDrawingVisible(value => !value)}>{drawingVisible ? '도면 숨김' : '도면 함께 보기'}</button>
|
||||
<button className={`drawing-toggle ${clipping ? 'active' : ''}`} onClick={() => setClipping(value => !value)}>{clipping ? '클리핑 해제' : '클리핑 켜기'}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="viewbar">
|
||||
@@ -112,7 +117,7 @@ export default function App() {
|
||||
<span>{visibleCount} / {allParts.length} 객체 표시</span>
|
||||
</div>
|
||||
<div className={`canvas-wrap ${renderMode ? 'render-mode' : ''}`}>
|
||||
<ModelViewer units={model.units} hidden={hidden} selected={selected} onSelect={setSelected} view={view} renderMode={renderMode} resetToken={resetToken} drawingVisible={drawingVisible} drawing={activeDrawing} drawingOpacity={drawingOpacity} />
|
||||
<ModelViewer units={model.units} hidden={hidden} selected={selected} onSelect={setSelected} view={view} renderMode={renderMode} resetToken={resetToken} drawingVisible={drawingVisible} drawing={activeDrawing} drawingOpacity={drawingOpacity} clipping={clipping} clipAxis={clipAxis} clipPosition={clipPosition} clipKeep={clipKeep} />
|
||||
<span className="canvas-tag">{renderMode ? '명암을 더한 도면 검토 시각화 · 실사 렌더링 아님' : '평면도·상부평면도 공통 구조물 모델'}</span>
|
||||
</div>
|
||||
{drawingVisible && <div className="drawing-controls">
|
||||
@@ -127,6 +132,21 @@ export default function App() {
|
||||
</label>
|
||||
<span>A-A/B-B는 해당 끝 측점 단면에 놓이며, 평면·종단 이미지는 CAD 좌표와 측점·EL 주석 기준으로 모델과 함께 투영됩니다. 평면 이미지는 화면 표시용 높이에 놓인 참고면입니다.</span>
|
||||
</div>}
|
||||
{clipping && <div className="clip-controls">
|
||||
<label>절단 축
|
||||
<select value={clipAxis} onChange={event => setClipAxis(event.target.value)}>
|
||||
<option value="x">X · 좌우 폭</option><option value="y">Y · 높이(EL)</option><option value="z">Z · 길이/측점 방향</option>
|
||||
</select>
|
||||
</label>
|
||||
<label className="clip-range">절단 위치 <input type="range" min="0" max="100" value={clipPosition} onChange={event => setClipPosition(Number(event.target.value))} /><b>{clipPosition}%</b></label>
|
||||
<label>남길 쪽
|
||||
<select value={clipKeep} onChange={event => setClipKeep(event.target.value)}>
|
||||
<option value="positive">축의 + 방향</option><option value="negative">축의 − 방향</option>
|
||||
</select>
|
||||
</label>
|
||||
<button className="clip-reset" onClick={() => { setClipPosition(50); setClipKeep('positive') }}>가운데로 초기화</button>
|
||||
<span>표면을 잘라 내부를 볼 수 있습니다. 절단면 덮개는 생성하지 않으며, 도면 이미지는 참고용으로 클리핑되지 않습니다.</span>
|
||||
</div>}
|
||||
<div className="viewer-foot"><span>끌기: 회전 · 휠: 확대/축소 · Shift+끌기 또는 오른쪽 끌기: 이동</span><button onClick={() => { setView('전체'); setResetToken(value => value + 1); setSelected(null) }}>전체 보기 ↗</button></div>
|
||||
<div className="selection" aria-live="polite">
|
||||
{selectedPart && selectedUnit ? <>
|
||||
|
||||
+37
-9
@@ -66,17 +66,33 @@ function inPolygon(point, polygon) {
|
||||
return inside
|
||||
}
|
||||
|
||||
export default function ModelViewer({ units, hidden, selected, onSelect, view, renderMode, resetToken, drawingVisible, drawing, drawingOpacity }) {
|
||||
function clipPolygon(points, axis, threshold, keepPositive) {
|
||||
const inside = point => keepPositive ? point[axis] >= threshold : point[axis] <= threshold
|
||||
const output = []
|
||||
for (let index = 0; index < points.length; index++) {
|
||||
const current = points[index]
|
||||
const previous = points[(index + points.length - 1) % points.length]
|
||||
const currentInside = inside(current), previousInside = inside(previous)
|
||||
if (currentInside !== previousInside) {
|
||||
const ratio = (threshold - previous[axis]) / (current[axis] - previous[axis])
|
||||
output.push(previous.map((value, coordinate) => value + (current[coordinate] - value) * ratio))
|
||||
}
|
||||
if (currentInside) output.push(current)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
export default function ModelViewer({ units, hidden, selected, onSelect, view, renderMode, resetToken, drawingVisible, drawing, drawingOpacity, clipping, clipAxis, clipPosition, clipKeep }) {
|
||||
const canvasRef = useRef(null)
|
||||
const cameraRef = useRef({ ...DEFAULT_CAMERA })
|
||||
const drawingImagesRef = useRef({})
|
||||
const sceneRef = useRef({ units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity })
|
||||
const sceneRef = useRef({ units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity, clipping, clipAxis, clipPosition, clipKeep })
|
||||
const drawRef = useRef(() => {})
|
||||
|
||||
useEffect(() => {
|
||||
sceneRef.current = { units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity }
|
||||
sceneRef.current = { units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity, clipping, clipAxis, clipPosition, clipKeep }
|
||||
drawRef.current()
|
||||
}, [units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity])
|
||||
}, [units, hidden, selected, view, renderMode, onSelect, drawingVisible, drawing, drawingOpacity, clipping, clipAxis, clipPosition, clipKeep])
|
||||
|
||||
useEffect(() => {
|
||||
const images = {}
|
||||
@@ -115,7 +131,7 @@ export default function ModelViewer({ units, hidden, selected, onSelect, view, r
|
||||
canvas.width = Math.round(width * dpr); canvas.height = Math.round(height * dpr)
|
||||
}
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
|
||||
const { units, hidden, selected, renderMode, drawingVisible, drawing, drawingOpacity } = sceneRef.current
|
||||
const { units, hidden, selected, renderMode, drawingVisible, drawing, drawingOpacity, clipping, clipAxis, clipPosition, clipKeep } = sceneRef.current
|
||||
const background = ctx.createLinearGradient(0, 0, 0, height)
|
||||
background.addColorStop(0, renderMode ? '#e8efea' : '#f8faf8')
|
||||
background.addColorStop(1, renderMode ? '#cbd8cf' : '#e9efea')
|
||||
@@ -129,7 +145,8 @@ export default function ModelViewer({ units, hidden, selected, onSelect, view, r
|
||||
for (let x = -40; x <= 40; x += 5) drawLine([x, 100.2, -22], [x, 100.2, 22], '#aab9ad38', .6)
|
||||
for (let z = -20; z <= 20; z += 5) drawLine([-40, 100.2, z], [40, 100.2, z], '#aab9ad38', .6)
|
||||
|
||||
const faces = []
|
||||
const sourceFaces = []
|
||||
const bounds = [[Infinity, -Infinity], [Infinity, -Infinity], [Infinity, -Infinity]]
|
||||
const longitudinalSteps = 8
|
||||
for (const unit of units) {
|
||||
for (const part of unit.parts) {
|
||||
@@ -145,13 +162,24 @@ export default function ModelViewer({ units, hidden, selected, onSelect, view, r
|
||||
worldPoint(unit, part.a, part.b, edge + 1, t1),
|
||||
worldPoint(unit, part.a, part.b, edge, t1),
|
||||
]
|
||||
const projected = points3d.map(point => project(point, width, height))
|
||||
const depth = projected.reduce((sum, point) => sum + point[2], 0) / projected.length
|
||||
faces.push({ projected, part, unit, color, depth, active, shade: .82 + .18 * Math.abs(Math.sin(edge * .73 + step * .11)) })
|
||||
points3d.forEach(point => point.forEach((value, axis) => {
|
||||
bounds[axis][0] = Math.min(bounds[axis][0], value)
|
||||
bounds[axis][1] = Math.max(bounds[axis][1], value)
|
||||
}))
|
||||
sourceFaces.push({ points3d, part, unit, color, active, shade: .82 + .18 * Math.abs(Math.sin(edge * .73 + step * .11)) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const axisIndex = { x: 0, y: 1, z: 2 }[clipAxis]
|
||||
const threshold = bounds[axisIndex][0] + (bounds[axisIndex][1] - bounds[axisIndex][0]) * clipPosition / 100
|
||||
const faces = sourceFaces.flatMap(face => {
|
||||
const points3d = clipping ? clipPolygon(face.points3d, axisIndex, threshold, clipKeep === 'positive') : face.points3d
|
||||
if (points3d.length < 3) return []
|
||||
const projected = points3d.map(point => project(point, width, height))
|
||||
const depth = projected.reduce((sum, point) => sum + point[2], 0) / projected.length
|
||||
return [{ ...face, projected, depth }]
|
||||
})
|
||||
faces.sort((a, b) => a.depth - b.depth)
|
||||
hitFaces = []
|
||||
for (const face of faces) {
|
||||
|
||||
@@ -52,6 +52,13 @@ h2 { margin:5px 0 0; font-size:16px; letter-spacing:-.04em; }
|
||||
.drawing-controls select { max-width:180px; padding:5px 7px; border:1px solid #d6e0d4; border-radius:5px; background:#fff; color:#526657; font-size:9px; }
|
||||
.drawing-controls input { width:95px; accent-color:#59785e; }
|
||||
.drawing-controls>span { color:#879287; font-size:8px; line-height:1.5; }
|
||||
.clip-controls { display:flex; align-items:center; flex-wrap:wrap; gap:9px 14px; padding:10px 15px; border-bottom:1px solid #e2e9dd; background:#f4f8f1; }
|
||||
.clip-controls label { display:flex; align-items:center; gap:7px; color:#526b58; font-size:9px; white-space:nowrap; }
|
||||
.clip-controls select { max-width:180px; padding:5px 7px; border:1px solid #d2dfd0; border-radius:5px; background:#fff; color:#526657; font-size:9px; }
|
||||
.clip-controls input { width:105px; accent-color:#59785e; }
|
||||
.clip-controls b { min-width:28px; color:#44694d; font-size:9px; }
|
||||
.clip-controls .clip-reset { padding:5px 8px; border:1px solid #d4dfd2; border-radius:5px; color:#58715d; font-size:9px; }
|
||||
.clip-controls>span { flex-basis:100%; color:#879287; font-size:8px; line-height:1.5; }
|
||||
.model-canvas { display:block; width:100%; height:485px; touch-action:none; cursor:grab; }
|
||||
.model-canvas:active { cursor:grabbing; }
|
||||
.model-canvas:focus-visible { outline:2px solid #7d9a83; outline-offset:-2px; }
|
||||
|
||||
Reference in new issue
Block a user