bightbranding commited on
Commit
ffeb37d
·
verified ·
1 Parent(s): 3115874

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +615 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Auto Photogrammetry Camera Tracker
3
- emoji: 👁
4
- colorFrom: blue
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: auto-photogrammetry-camera-tracker
3
+ emoji: 🐳
4
+ colorFrom: gray
5
+ colorTo: yellow
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,615 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="fa" dir="rtl">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Auto Photogrammetry Camera Tracker - نسخه وب</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
9
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Vazirmatic:wght@300;400;500;700&display=swap');
12
+
13
+ body {
14
+ font-family: 'Vazirmatic', sans-serif;
15
+ }
16
+
17
+ .perspective-1000 {
18
+ perspective: 1000px;
19
+ }
20
+
21
+ .transform-style-3d {
22
+ transform-style: preserve-3d;
23
+ }
24
+
25
+ .rotate-y-15 {
26
+ transform: rotateY(15deg);
27
+ }
28
+
29
+ .glass-effect {
30
+ background: rgba(255, 255, 255, 0.05);
31
+ backdrop-filter: blur(10px);
32
+ border: 1px solid rgba(255, 255, 255, 0.1);
33
+ }
34
+
35
+ .progress-ring {
36
+ transform: rotate(-90deg);
37
+ }
38
+
39
+ .progress-ring__circle {
40
+ transition: stroke-dashoffset 0.35s;
41
+ transform-origin: 50% 50%;
42
+ }
43
+
44
+ .point-cloud {
45
+ position: absolute;
46
+ top: 0;
47
+ left: 0;
48
+ width: 100%;
49
+ height: 100%;
50
+ pointer-events: none;
51
+ }
52
+
53
+ .floating-ui {
54
+ animation: float 6s ease-in-out infinite;
55
+ }
56
+
57
+ @keyframes float {
58
+ 0%, 100% { transform: translateY(0px); }
59
+ 50% { transform: translateY(-10px); }
60
+ }
61
+
62
+ .glow-effect {
63
+ box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
64
+ }
65
+
66
+ .scan-line {
67
+ background: linear-gradient(90deg,
68
+ transparent 0%,
69
+ rgba(59, 130, 246, 0.8) 50%,
70
+ transparent 100%);
71
+ animation: scan 2s linear infinite;
72
+ }
73
+
74
+ @keyframes scan {
75
+ 0% { transform: translateX(-100%); }
76
+ 100% { transform: translateX(100%); }
77
+ }
78
+ </style>
79
+ </head>
80
+ <body class="bg-gray-900 text-white min-h-screen overflow-x-hidden">
81
+ <!-- Background Animation -->
82
+ <div id="background-animation" class="fixed inset-0 z-0"></div>
83
+
84
+ <div class="relative z-10">
85
+ <!-- Header -->
86
+ <header class="glass-effect border-b border-gray-700">
87
+ <div class="container mx-auto px-4 py-6">
88
+ <div class="flex items-center justify-between">
89
+ <div class="flex items-center space-x-4">
90
+ <div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
91
+ <span class="text-white font-bold text-xl">3D</span>
92
+ </div>
93
+ <div>
94
+ <h1 class="text-2xl font-bold">Auto Photogrammetry Camera Tracker</h1>
95
+ <p class="text-gray-400 text-sm">تبدیل ویدیو به محیط سه‌بعدی با هوش مصنوعی</p>
96
+ </div>
97
+ </div>
98
+ <div class="flex items-center space-x-4">
99
+ <button id="settingsBtn" class="p-2 rounded-lg bg-gray-800 hover:bg-gray-700 transition-colors">
100
+ <span class="material-icons">settings</span>
101
+ </button>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </header>
106
+
107
+ <!-- Main Content -->
108
+ <main class="container mx-auto px-4 py-8">
109
+ <div class="grid lg:grid-cols-3 gap-8">
110
+ <!-- Control Panel -->
111
+ <div class="lg:col-span-1 space-y-6">
112
+ <!-- Upload Section -->
113
+ <div class="glass-effect rounded-xl p-6">
114
+ <h3 class="text-lg font-semibold mb-4 flex items-center">
115
+ <span class="material-icons mr-2">upload</span>
116
+ بارگذاری ویدیو
117
+ </h3>
118
+ <div id="uploadArea" class="border-2 border-dashed border-gray-600 rounded-lg p-8 text-center hover:border-blue-500 transition-colors cursor-pointer">
119
+ <span class="material-icons text-6xl text-gray-400 mb-4">video_library</span>
120
+ <p class="text-gray-300">ویدیو خود را اینجا رها کنید یا کلیک کنید</p>
121
+ <input type="file" id="videoInput" accept="video/*" class="hidden">
122
+ </div>
123
+ <div id="videoInfo" class="hidden mt-4 p-4 bg-gray-800 rounded-lg">
124
+ <p class="text-sm text-gray-300">
125
+ <strong>نام فایل:</strong> <span id="fileName">-</span><br>
126
+ <strong>اندازه:</strong> <span id="fileSize">-</span><br>
127
+ <strong>مدت زمان:</strong> <span id="duration">-</span>
128
+ </p>
129
+ </div>
130
+ </div>
131
+
132
+ <!-- Settings Panel -->
133
+ <div class="glass-effect rounded-xl p-6">
134
+ <h3 class="text-lg font-semibold mb-4 flex items-center">
135
+ <span class="material-icons mr-2">tune</span>
136
+ تنظیمات پردازش
137
+ </h3>
138
+ <div class="space-y-4">
139
+ <div>
140
+ <label class="block text-sm font-medium mb-2">نرخ نمونه‌برداری فریم</label>
141
+ <input type="range" id="frameRate" min="1" max="30" value="5" class="w-full">
142
+ <span class="text-sm text-gray-400">هر <span id="frameRateValue">5</span> فریم</span>
143
+ </div>
144
+ <div>
145
+ <label class="block text-sm font-medium mb-2">آستانه تطابق</label>
146
+ <input type="range" id="matchThreshold" min="0.1" max="1" step="0.1" value="0.7" class="w-full">
147
+ <span class="text-sm text-gray-400"><span id="thresholdValue">0.7</span></span>
148
+ </div>
149
+ <div>
150
+ <label class="block text-sm font-medium mb-2">طول کانونی (mm)</label>
151
+ <input type="number" id="focalLength" value="35" class="w-full bg-gray-800 rounded px-3 py-2">
152
+ </div>
153
+ <div class="flex items-center">
154
+ <input type="checkbox" id="lensCorrection" class="mr-2">
155
+ <label class="text-sm">اصلاح اعوجاج لنز</label>
156
+ </div>
157
+ </div>
158
+ </div>
159
+
160
+ <!-- Process Button -->
161
+ <button id="processBtn" disabled class="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 disabled:from-gray-600 disabled:to-gray-700 disabled:cursor-not-allowed rounded-xl p-4 font-semibold transition-all glow-effect">
162
+ <span class="material-icons mr-2">play_circle</span>
163
+ شروع پردازش
164
+ </button>
165
+
166
+ <!-- Progress Section -->
167
+ <div id="progressSection" class="glass-effect rounded-xl p-6 hidden">
168
+ <h3 class="text-lg font-semibold mb-4">پردازش...</h3>
169
+ <div class="space-y-4">
170
+ <div>
171
+ <div class="flex justify-between text-sm mb-1">
172
+ <span>استخراج فریم‌ها</span>
173
+ <span id="progress1">0%</span>
174
+ </div>
175
+ <div class="w-full bg-gray-700 rounded-full h-2">
176
+ <div id="bar1" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
177
+ </div>
178
+ </div>
179
+ <div>
180
+ <div class="flex justify-between text-sm mb-1">
181
+ <span>تشخیص ویژگی‌ها</span>
182
+ <span id="progress2">0%</span>
183
+ </div>
184
+ <div class="w-full bg-gray-700 rounded-full h-2">
185
+ <div id="bar2" class="bg-purple-500 h-2 rounded-full" style="width: 0%"></div>
186
+ </div>
187
+ </div>
188
+ <div>
189
+ <div class="flex justify-between text-sm mb-1">
190
+ <span>ساخت نقطه‌ابر</span>
191
+ <span id="progress3">0%</span>
192
+ </div>
193
+ <div class="w-full bg-gray-700 rounded-full h-2">
194
+ <div id="bar3" class="bg-green-500 h-2 rounded-full" style="width: 0%"></div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ </div>
199
+ </div>
200
+
201
+ <!-- 3D Viewer -->
202
+ <div class="lg:col-span-2">
203
+ <div class="glass-effect rounded-xl p-6 h-full">
204
+ <div class="flex justify-between items-center mb-4">
205
+ <h3 class="text-lg font-semibold flex items-center">
206
+ <span class="material-icons mr-2">view_in_ar</span>
207
+ پیش‌نمایش سه‌بعدی
208
+ </h3>
209
+ <div class="flex space-x-2">
210
+ <button id="resetView" class="p-2 bg-gray-800 rounded hover:bg-gray-700">
211
+ <span class="material-icons text-sm">refresh</span>
212
+ </button>
213
+ <button id="toggleWireframe" class="p-2 bg-gray-800 rounded hover:bg-gray-700">
214
+ <span class="material-icons text-sm">grid_3x3</span>
215
+ </button>
216
+ </div>
217
+ </div>
218
+
219
+ <div id="viewer3d" class="relative bg-gray-800 rounded-lg h-96 lg:h-[500px]">
220
+ <div id="threejs-container" class="w-full h-full rounded-lg overflow-hidden"></div>
221
+
222
+ <!-- Point Cloud Overlay -->
223
+ <div id="pointCloudOverlay" class="point-cloud hidden">
224
+ <canvas id="pointCloudCanvas" class="w-full h-full"></canvas>
225
+ </div>
226
+
227
+ <!-- Camera Path Indicator -->
228
+ <div id="cameraPath" class="absolute inset-0 hidden">
229
+ <svg class="w-full h-full" viewBox="0 0 400 300">
230
+ <path id="cameraPathSvg" stroke="#3B82F6" stroke-width="2" fill="none" opacity="0.7"/>
231
+ <circle id="cameraPos" r="4" fill="#3B82F6" class="glow-effect"/>
232
+ </svg>
233
+ </div>
234
+ </div>
235
+
236
+ <!-- Stats Panel -->
237
+ <div class="mt-4 grid grid-cols-2 lg:grid-cols-4 gap-4">
238
+ <div class="glass-effect rounded-lg p-4 text-center">
239
+ <span class="material-icons text-blue-500 mb-2">photo_camera</span>
240
+ <p class="text-sm text-gray-400">فریم‌های پردازش شده</p>
241
+ <p id="framesProcessed" class="text-xl font-bold">0</p>
242
+ </div>
243
+ <div class="glass-effect rounded-lg p-4 text-center">
244
+ <span class="material-icons text-purple-500 mb-2">grain</span>
245
+ <p class="text-sm text-gray-400">نقاط سه‌بعدی</p>
246
+ <p id="pointsCount" class="text-xl font-bold">0</p>
247
+ </div>
248
+ <div class="glass-effect rounded-lg p-4 text-center">
249
+ <span class="material-icons text-green-500 mb-2">timeline</span>
250
+ <p class="text-sm text-gray-400">ترکینگ دوربین</p>
251
+ <p id="trackingStatus" class="text-sm">غیرفعال</p>
252
+ </div>
253
+ <div class="glass-effect rounded-lg p-4 text-center">
254
+ <span class="material-icons text-orange-500 mb-2">memory</span>
255
+ <p class="text-sm text-gray-400">زمان پردازش</p>
256
+ <p id="processingTime" class="text-xl font-bold">0s</p>
257
+ </div>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ </div>
262
+ </main>
263
+
264
+ <!-- Results Modal -->
265
+ <div id="resultsModal" class="fixed inset-0 bg-black bg-opacity-75 z-50 hidden flex items-center justify-center">
266
+ <div class="glass-effect rounded-xl p-8 max-w-2xl w-full mx-4">
267
+ <div class="text-center">
268
+ <div class="w-20 h-20 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-4">
269
+ <span class="material-icons text-4xl">check_circle</span>
270
+ </div>
271
+ <h2 class="text-2xl font-bold mb-4">پردازش با موفقیت انجام شد!</h2>
272
+ <p class="text-gray-300 mb-6">محیط سه‌بعدی از ویدیوی شما با موفقیت ساخته شد</p>
273
+
274
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
275
+ <div class="glass-effect rounded-lg p-4">
276
+ <p class="text-2xl font-bold text-blue-400" id="finalFrames">0</p>
277
+ <p class="text-sm text-gray-400">فریم پردازش شده</p>
278
+ </div>
279
+ <div class="glass-effect rounded-lg p-4">
280
+ <p class="text-2xl font-bold text-purple-400" id="finalPoints">0</p>
281
+ <p class="text-sm text-gray-400">نقطه سه‌بعدی</p>
282
+ </div>
283
+ <div class="glass-effect rounded-lg p-4">
284
+ <p class="text-2xl font-bold text-green-400" id="finalTime">0s</p>
285
+ <p class="text-sm text-gray-400">زمان کل</p>
286
+ </div>
287
+ </div>
288
+
289
+ <div class="flex justify-center space-x-4">
290
+ <button id="downloadBtn" class="bg-blue-600 hover:bg-blue-700 px-6 py-2 rounded-lg transition-colors">
291
+ <span class="material-icons mr-2">download</span>
292
+ دانلود نتایج
293
+ </button>
294
+ <button id="closeModal" class="bg-gray-700 hover:bg-gray-600 px-6 py-2 rounded-lg transition-colors">
295
+ بستن
296
+ </button>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+ </div>
302
+
303
+ <script>
304
+ // Global variables
305
+ let scene, camera, renderer, pointCloud;
306
+ let animationId;
307
+ let processingStartTime;
308
+
309
+ // Initialize Three.js scene
310
+ function init3DViewer() {
311
+ const container = document.getElementById('threejs-container');
312
+
313
+ // Scene setup
314
+ scene = new THREE.Scene();
315
+ scene.background = new THREE.Color(0x1a1a1a);
316
+
317
+ // Camera setup
318
+ camera = new THREE.PerspectiveCamera(
319
+ 75,
320
+ container.clientWidth / container.clientHeight,
321
+ 0.1,
322
+ 1000
323
+ );
324
+ camera.position.set(5, 5, 5);
325
+ camera.lookAt(0, 0, 0);
326
+
327
+ // Renderer setup
328
+ renderer = new THREE.WebGLRenderer({ antialias: true });
329
+ renderer.setSize(container.clientWidth, container.clientHeight);
330
+ container.appendChild(renderer.domElement);
331
+
332
+ // Add grid
333
+ const gridHelper = new THREE.GridHelper(10, 10, 0x444444, 0x444444);
334
+ scene.add(gridHelper);
335
+
336
+ // Add axes helper
337
+ const axesHelper = new THREE.AxesHelper(5);
338
+ scene.add(axesHelper);
339
+
340
+ // Add lights
341
+ const ambientLight = new THREE.AmbientLight(0x404040);
342
+ scene.add(ambientLight);
343
+
344
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
345
+ directionalLight.position.set(5, 5, 5);
346
+ scene.add(directionalLight);
347
+
348
+ // Create initial point cloud
349
+ createPointCloud();
350
+
351
+ // Animation loop
352
+ animate();
353
+ }
354
+
355
+ function createPointCloud() {
356
+ const geometry = new THREE.BufferGeometry();
357
+ const positions = [];
358
+ const colors = [];
359
+
360
+ // Generate random points
361
+ for (let i = 0; i < 1000; i++) {
362
+ positions.push(
363
+ (Math.random() - 0.5) * 10,
364
+ Math.random() * 5,
365
+ (Math.random() - 0.5) * 10
366
+ );
367
+
368
+ const color = new THREE.Color();
369
+ color.setHSL(Math.random(), 0.7, 0.5);
370
+ colors.push(color.r, color.g, color.b);
371
+ }
372
+
373
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
374
+ geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
375
+
376
+ const material = new THREE.PointsMaterial({
377
+ size: 0.05,
378
+ vertexColors: true,
379
+ opacity: 0.8,
380
+ transparent: true
381
+ });
382
+
383
+ pointCloud = new THREE.Points(geometry, material);
384
+ scene.add(pointCloud);
385
+ }
386
+
387
+ function animate() {
388
+ animationId = requestAnimationFrame(animate);
389
+
390
+ if (pointCloud) {
391
+ pointCloud.rotation.y += 0.001;
392
+ }
393
+
394
+ renderer.render(scene, camera);
395
+ }
396
+
397
+ // Handle window resize
398
+ window.addEventListener('resize', () => {
399
+ if (renderer && camera) {
400
+ const container = document.getElementById('threejs-container');
401
+ camera.aspect = container.clientWidth / container.clientHeight;
402
+ camera.updateProjectionMatrix();
403
+ renderer.setSize(container.clientWidth, container.clientHeight);
404
+ }
405
+ });
406
+
407
+ // UI interactions
408
+ document.addEventListener('DOMContentLoaded', () => {
409
+ init3DViewer();
410
+
411
+ // File upload handling
412
+ const uploadArea = document.getElementById('uploadArea');
413
+ const videoInput = document.getElementById('videoInput');
414
+ const processBtn = document.getElementById('processBtn');
415
+
416
+ uploadArea.addEventListener('click', () => videoInput.click());
417
+ uploadArea.addEventListener('dragover', (e) => {
418
+ e.preventDefault();
419
+ uploadArea.classList.add('border-blue-500');
420
+ });
421
+ uploadArea.addEventListener('dragleave', () => {
422
+ uploadArea.classList.remove('border-blue-500');
423
+ });
424
+ uploadArea.addEventListener('drop', (e) => {
425
+ e.preventDefault();
426
+ uploadArea.classList.remove('border-blue-500');
427
+ handleFile(e.dataTransfer.files[0]);
428
+ });
429
+
430
+ videoInput.addEventListener('change', (e) => {
431
+ handleFile(e.target.files[0]);
432
+ });
433
+
434
+ function handleFile(file) {
435
+ if (file && file.type.startsWith('video/')) {
436
+ const video = document.createElement('video');
437
+ video.src = URL.createObjectURL(file);
438
+ video.addEventListener('loadedmetadata', () => {
439
+ document.getElementById('fileName').textContent = file.name;
440
+ document.getElementById('fileSize').textContent = (file.size / 1024 / 1024).toFixed(2) + ' MB';
441
+ document.getElementById('duration').textContent = Math.floor(video.duration) + ' ثانیه';
442
+ document.getElementById('videoInfo').classList.remove('hidden');
443
+ processBtn.disabled = false;
444
+ });
445
+ }
446
+ }
447
+
448
+ // Settings sliders
449
+ document.getElementById('frameRate').addEventListener('input', (e) => {
450
+ document.getElementById('frameRateValue').textContent = e.target.value;
451
+ });
452
+
453
+ document.getElementById('matchThreshold').addEventListener('input', (e) => {
454
+ document.getElementById('thresholdValue').textContent = e.target.value;
455
+ });
456
+
457
+ // Process button
458
+ processBtn.addEventListener('click', startProcessing);
459
+
460
+ // Modal controls
461
+ document.getElementById('closeModal').addEventListener('click', () => {
462
+ document.getElementById('resultsModal').classList.add('hidden');
463
+ });
464
+
465
+ document.getElementById('downloadBtn').addEventListener('click', () => {
466
+ alert('در نسخه واقعی: دانلود فایل‌های خروجی Blender');
467
+ });
468
+ });
469
+
470
+ // Processing simulation
471
+ function startProcessing() {
472
+ processingStartTime = Date.now();
473
+ document.getElementById('progressSection').classList.remove('hidden');
474
+ document.getElementById('processBtn').disabled = true;
475
+
476
+ const steps = [
477
+ { id: 'bar1', progress: 'progress1', duration: 2000 },
478
+ { id: 'bar2', progress: 'progress2', duration: 3000 },
479
+ { id: 'bar3', progress: 'progress3', duration: 2500 }
480
+ ];
481
+
482
+ let completedSteps = 0;
483
+
484
+ steps.forEach((step, index) => {
485
+ let progress = 0;
486
+ const interval = setInterval(() => {
487
+ progress += 1;
488
+ const percent = Math.min(progress, 100);
489
+ document.getElementById(step.id).style.width = percent + '%';
490
+ document.getElementById(step.progress).textContent = percent + '%';
491
+
492
+ // Update stats
493
+ if (index === 0) {
494
+ document.getElementById('framesProcessed').textContent = Math.floor(percent * 2.4);
495
+ } else if (index === 1) {
496
+ document.getElementById('pointsCount').textContent = Math.floor(percent * 30);
497
+ }
498
+
499
+ if (progress >= 100) {
500
+ clearInterval(interval);
501
+ completedSteps++;
502
+
503
+ if (completedSteps === steps.length) {
504
+ finishProcessing();
505
+ }
506
+ }
507
+ }, step.duration / 100);
508
+ });
509
+ }
510
+
511
+ function finishProcessing() {
512
+ const totalTime = Math.floor((Date.now() - processingStartTime) / 1000);
513
+ document.getElementById('processingTime').textContent = totalTime + 's';
514
+ document.getElementById('trackingStatus').textContent = 'فعال';
515
+
516
+ // Update final stats
517
+ document.getElementById('finalFrames').textContent = document.getElementById('framesProcessed').textContent;
518
+ document.getElementById('finalPoints').textContent = document.getElementById('pointsCount').textContent;
519
+ document.getElementById('finalTime').textContent = totalTime + 's';
520
+
521
+ // Show camera path
522
+ document.getElementById('cameraPath').classList.remove('hidden');
523
+ animateCameraPath();
524
+
525
+ // Show results modal after delay
526
+ setTimeout(() => {
527
+ document.getElementById('resultsModal').classList.remove('hidden');
528
+ }, 1000);
529
+ }
530
+
531
+ function animateCameraPath() {
532
+ const path = document.getElementById('cameraPathSvg');
533
+ const pos = document.getElementById('cameraPos');
534
+
535
+ // Create a simple camera path
536
+ let d = 'M 50 250';
537
+ for (let i = 0; i < 300; i += 10) {
538
+ const x = 50 + i;
539
+ const y = 250 + Math.sin(i * 0.02) * 50;
540
+ d += ` L ${x} ${y}`;
541
+ }
542
+ path.setAttribute('d', d);
543
+
544
+ // Animate camera position
545
+ let progress = 0;
546
+ const animateCamera = () => {
547
+ progress += 0.01;
548
+ if (progress > 1) progress = 0;
549
+
550
+ const point = path.getPointAtLength(progress * path.getTotalLength());
551
+ pos.setAttribute('cx', point.x);
552
+ pos.setAttribute('cy', point.y);
553
+
554
+ requestAnimationFrame(animateCamera);
555
+ };
556
+ animateCamera();
557
+ }
558
+
559
+ // Background animation
560
+ function createBackgroundAnimation() {
561
+ const canvas = document.createElement('canvas');
562
+ const ctx = canvas.getContext('2d');
563
+ const container = document.getElementById('background-animation');
564
+
565
+ canvas.width = window.innerWidth;
566
+ canvas.height = window.innerHeight;
567
+ canvas.style.position = 'absolute';
568
+ canvas.style.top = '0';
569
+ canvas.style.left = '0';
570
+ canvas.style.width = '100%';
571
+ canvas.style.height = '100%';
572
+
573
+ container.appendChild(canvas);
574
+
575
+ const particles = [];
576
+ const particleCount = 100;
577
+
578
+ for (let i = 0; i < particleCount; i++) {
579
+ particles.push({
580
+ x: Math.random() * canvas.width,
581
+ y: Math.random() * canvas.height,
582
+ vx: (Math.random() - 0.5) * 0.5,
583
+ vy: (Math.random() - 0.5) * 0.5,
584
+ size: Math.random() * 2 + 1,
585
+ opacity: Math.random() * 0.5 + 0.1
586
+ });
587
+ }
588
+
589
+ function animate() {
590
+ ctx.fillStyle = 'rgba(26, 26, 26, 0.1)';
591
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
592
+
593
+ particles.forEach(particle => {
594
+ particle.x += particle.vx;
595
+ particle.y += particle.vy;
596
+
597
+ if (particle.x < 0 || particle.x > canvas.width) particle.vx *= -1;
598
+ if (particle.y < 0 || particle.y > canvas.height) particle.vy *= -1;
599
+
600
+ ctx.beginPath();
601
+ ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
602
+ ctx.fillStyle = `rgba(59, 130, 246, ${particle.opacity})`;
603
+ ctx.fill();
604
+ });
605
+
606
+ requestAnimationFrame(animate);
607
+ }
608
+
609
+ animate();
610
+ }
611
+
612
+ createBackgroundAnimation();
613
+ </script>
614
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=bightbranding/auto-photogrammetry-camera-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
615
+ </html>