ignaciomdr commited on
Commit
bac1411
verified
1 Parent(s): b40c867

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +416 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Fotokmz
3
- emoji: 馃搱
4
- colorFrom: green
5
- colorTo: gray
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: fotokmz
3
+ emoji: 馃惓
4
+ colorFrom: blue
5
+ colorTo: blue
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,416 @@
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="es">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Foto a KML con UTM WGS84 Zona 18S</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.8.0/proj4.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ #videoElement {
12
+ transform: scaleX(-1);
13
+ }
14
+ #canvasElement {
15
+ transform: scaleX(-1);
16
+ display: none;
17
+ }
18
+ #canvasWithOverlay {
19
+ display: none;
20
+ }
21
+ .hidden {
22
+ display: none;
23
+ }
24
+ .kml-download {
25
+ animation: pulse 2s infinite;
26
+ }
27
+ .photo-overlay {
28
+ position: absolute;
29
+ bottom: 0;
30
+ left: 0;
31
+ right: 0;
32
+ background: rgba(0, 0, 0, 0.7);
33
+ color: white;
34
+ padding: 10px;
35
+ font-family: Arial, sans-serif;
36
+ }
37
+ .photo-title {
38
+ font-size: 18px;
39
+ font-weight: bold;
40
+ margin-bottom: 5px;
41
+ text-align: center;
42
+ }
43
+ .photo-coords {
44
+ font-size: 14px;
45
+ text-align: center;
46
+ }
47
+ @keyframes pulse {
48
+ 0% { transform: scale(1); }
49
+ 50% { transform: scale(1.05); }
50
+ 100% { transform: scale(1); }
51
+ }
52
+ </style>
53
+ </head>
54
+ <body class="bg-gray-100 min-h-screen">
55
+ <div class="container mx-auto px-4 py-8">
56
+ <div class="max-w-2xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
57
+ <div class="p-8">
58
+ <h1 class="text-3xl font-bold text-center text-blue-600 mb-6">
59
+ <i class="fas fa-camera-retro mr-2"></i> Foto a KML con UTM WGS84 Zona 18S
60
+ </h1>
61
+
62
+ <div class="mb-6 bg-blue-50 p-4 rounded-lg">
63
+ <h2 class="text-xl font-semibold text-blue-800 mb-2">
64
+ <i class="fas fa-info-circle mr-2"></i>Instrucciones:
65
+ </h2>
66
+ <ol class="list-decimal pl-5 space-y-2 text-gray-700">
67
+ <li>Permite el acceso a la c谩mara cuando se te solicite.</li>
68
+ <li>Enfoca lo que quieras capturar en la vista previa.</li>
69
+ <li>Haz clic en "Tomar Foto" para capturar la imagen.</li>
70
+ <li>La aplicaci贸n obtendr谩 autom谩ticamente tu ubicaci贸n.</li>
71
+ <li>Haz clic en "Generar KML" para descargar el archivo con la foto y coordenadas UTM WGS84 Zona 18S.</li>
72
+ </ol>
73
+ </div>
74
+
75
+ <!-- Vista de c谩mara -->
76
+ <div id="cameraView" class="mb-6">
77
+ <div class="relative bg-black rounded-lg overflow-hidden">
78
+ <video id="videoElement" autoplay playsinline class="w-full h-auto"></video>
79
+ <canvas id="canvasElement"></canvas>
80
+ <canvas id="canvasWithOverlay"></canvas>
81
+ <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4">
82
+ <button id="captureBtn" class="w-16 h-16 mx-auto bg-white rounded-full flex items-center justify-center shadow-lg hover:bg-gray-100 transition">
83
+ <i class="fas fa-camera text-2xl text-gray-800"></i>
84
+ </button>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Vista de foto capturada -->
90
+ <div id="photoView" class="hidden mb-6">
91
+ <div class="relative bg-gray-200 rounded-lg overflow-hidden">
92
+ <img id="photoResult" src="" alt="Foto capturada" class="w-full h-auto">
93
+ <div id="photoOverlay" class="photo-overlay">
94
+ <div class="photo-title">Obra Q72 Ampliaci贸n Ruta S-839</div>
95
+ <div id="utmCoords" class="photo-coords"></div>
96
+ </div>
97
+ <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/70 to-transparent p-4 flex justify-between items-center">
98
+ <button id="retakeBtn" class="px-4 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition">
99
+ <i class="fas fa-redo mr-2"></i>Volver a tomar
100
+ </button>
101
+ <div class="text-white">
102
+ <i class="fas fa-map-marker-alt mr-2"></i>
103
+ <span id="locationInfo">Obteniendo ubicaci贸n...</span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Controles -->
110
+ <div class="flex flex-col space-y-4">
111
+ <button id="generateKmlBtn" class="hidden kml-download px-6 py-3 bg-green-600 text-white rounded-lg font-semibold hover:bg-green-700 transition flex items-center justify-center">
112
+ <i class="fas fa-file-download mr-2"></i> Generar y Descargar KML
113
+ </button>
114
+
115
+ <div id="errorMsg" class="hidden bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded">
116
+ <i class="fas fa-exclamation-triangle mr-2"></i>
117
+ <span id="errorText"></span>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <script>
125
+ // Definir proyecciones UTM Zona 18 Sur (EPSG:32718)
126
+ proj4.defs("EPSG:4326", "+proj=longlat +datum=WGS84 +no_defs");
127
+ proj4.defs("EPSG:32718", "+proj=utm +zone=18 +south +datum=WGS84 +units=m +no_defs");
128
+
129
+ // Elementos del DOM
130
+ const videoElement = document.getElementById('videoElement');
131
+ const canvasElement = document.getElementById('canvasElement');
132
+ const canvasWithOverlay = document.getElementById('canvasWithOverlay');
133
+ const photoResult = document.getElementById('photoResult');
134
+ const captureBtn = document.getElementById('captureBtn');
135
+ const retakeBtn = document.getElementById('retakeBtn');
136
+ const generateKmlBtn = document.getElementById('generateKmlBtn');
137
+ const cameraView = document.getElementById('cameraView');
138
+ const photoView = document.getElementById('photoView');
139
+ const locationInfo = document.getElementById('locationInfo');
140
+ const errorMsg = document.getElementById('errorMsg');
141
+ const errorText = document.getElementById('errorText');
142
+ const photoOverlay = document.getElementById('photoOverlay');
143
+ const utmCoords = document.getElementById('utmCoords');
144
+
145
+ // Variables de estado
146
+ let photoDataUrl = '';
147
+ let photoWithOverlayDataUrl = '';
148
+ let currentLocation = null;
149
+ let photoDateTime = '';
150
+
151
+ // Iniciar c谩mara
152
+ async function startCamera() {
153
+ try {
154
+ const stream = await navigator.mediaDevices.getUserMedia({
155
+ video: { facingMode: 'environment' },
156
+ audio: false
157
+ });
158
+ videoElement.srcObject = stream;
159
+ } catch (err) {
160
+ showError('No se pudo acceder a la c谩mara. Aseg煤rate de haber dado los permisos necesarios.');
161
+ console.error('Error al acceder a la c谩mara:', err);
162
+ }
163
+ }
164
+
165
+ // Funci贸n para convertir grados decimales a UTM Zona 18 Sur (EPSG:32718)
166
+ function toUTM(lat, lng) {
167
+ try {
168
+ // Convertir de WGS84 (EPSG:4326) a UTM Zona 18 Sur (EPSG:32718)
169
+ const utmCoords = proj4("EPSG:4326", "EPSG:32718", [lng, lat]);
170
+
171
+ return {
172
+ zone: 18,
173
+ hemisphere: 'S',
174
+ easting: utmCoords[0].toFixed(2),
175
+ northing: utmCoords[1].toFixed(2)
176
+ };
177
+ } catch (error) {
178
+ console.error('Error en conversi贸n UTM:', error);
179
+ return {
180
+ zone: 18,
181
+ hemisphere: 'S',
182
+ easting: 'N/A',
183
+ northing: 'N/A'
184
+ };
185
+ }
186
+ }
187
+
188
+ // Capturar foto y agregar overlay
189
+ function capturePhoto() {
190
+ const context = canvasElement.getContext('2d');
191
+ canvasElement.width = videoElement.videoWidth;
192
+ canvasElement.height = videoElement.videoHeight;
193
+ context.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
194
+
195
+ photoDataUrl = canvasElement.toDataURL('image/jpeg');
196
+ photoResult.src = photoDataUrl;
197
+
198
+ // Obtener fecha y hora actual
199
+ const now = new Date();
200
+ photoDateTime = now.toISOString();
201
+
202
+ // Cambiar vistas
203
+ cameraView.classList.add('hidden');
204
+ photoView.classList.remove('hidden');
205
+
206
+ // Obtener ubicaci贸n
207
+ getLocation();
208
+ }
209
+
210
+ // Crear imagen con overlay de coordenadas
211
+ function createImageWithOverlay() {
212
+ return new Promise((resolve) => {
213
+ const img = new Image();
214
+ img.onload = function() {
215
+ // Configurar canvas con overlay
216
+ canvasWithOverlay.width = img.width;
217
+ canvasWithOverlay.height = img.height;
218
+ const ctx = canvasWithOverlay.getContext('2d');
219
+
220
+ // Dibujar la imagen original
221
+ ctx.drawImage(img, 0, 0);
222
+
223
+ // Configurar estilo para el texto
224
+ ctx.font = 'bold 24px Arial';
225
+ ctx.fillStyle = 'white';
226
+ ctx.textAlign = 'center';
227
+ ctx.textBaseline = 'bottom';
228
+
229
+ // Dibujar fondo semitransparente para el texto
230
+ const text = "Obra Q72 Ampliaci贸n Ruta S-839";
231
+ const textWidth = ctx.measureText(text).width;
232
+ const padding = 20;
233
+ const rectHeight = 80;
234
+
235
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
236
+ ctx.fillRect(
237
+ (canvasWithOverlay.width - textWidth - padding * 2) / 2,
238
+ canvasWithOverlay.height - rectHeight - 10,
239
+ textWidth + padding * 2,
240
+ rectHeight
241
+ );
242
+
243
+ // Dibujar t铆tulo
244
+ ctx.fillStyle = 'white';
245
+ ctx.font = 'bold 24px Arial';
246
+ ctx.fillText(
247
+ "Obra Q72 Ampliaci贸n Ruta S-839",
248
+ canvasWithOverlay.width / 2,
249
+ canvasWithOverlay.height - 50
250
+ );
251
+
252
+ // Dibujar coordenadas UTM Zona 18S
253
+ if (currentLocation) {
254
+ const utm = toUTM(currentLocation.lat, currentLocation.lng);
255
+ const coordsText = `UTM WGS84 Zona ${utm.zone}${utm.hemisphere} Este: ${utm.easting} Norte: ${utm.northing}`;
256
+
257
+ ctx.font = '18px Arial';
258
+ ctx.fillText(
259
+ coordsText,
260
+ canvasWithOverlay.width / 2,
261
+ canvasWithOverlay.height - 20
262
+ );
263
+ }
264
+
265
+ // Obtener la imagen con overlay como Data URL
266
+ photoWithOverlayDataUrl = canvasWithOverlay.toDataURL('image/jpeg');
267
+ resolve(photoWithOverlayDataUrl);
268
+ };
269
+ img.src = photoDataUrl;
270
+ });
271
+ }
272
+
273
+ // Obtener ubicaci贸n
274
+ function getLocation() {
275
+ if (navigator.geolocation) {
276
+ locationInfo.textContent = 'Obteniendo ubicaci贸n...';
277
+
278
+ navigator.geolocation.getCurrentPosition(
279
+ async (position) => {
280
+ currentLocation = {
281
+ lat: position.coords.latitude,
282
+ lng: position.coords.longitude,
283
+ alt: position.coords.altitude || 0
284
+ };
285
+
286
+ // Convertir a UTM Zona 18S usando proj4js
287
+ const utm = toUTM(currentLocation.lat, currentLocation.lng);
288
+
289
+ // Mostrar en el overlay
290
+ locationInfo.textContent = `UTM WGS84 Zona ${utm.zone}${utm.hemisphere}`;
291
+ utmCoords.textContent = `Este: ${utm.easting} Norte: ${utm.northing}`;
292
+
293
+ // Crear imagen con overlay
294
+ await createImageWithOverlay();
295
+
296
+ // Mostrar bot贸n de generar KML
297
+ generateKmlBtn.classList.remove('hidden');
298
+ },
299
+ (error) => {
300
+ let errorMessage = 'No se pudo obtener la ubicaci贸n.';
301
+ switch(error.code) {
302
+ case error.PERMISSION_DENIED:
303
+ errorMessage = 'Permiso de ubicaci贸n denegado.';
304
+ break;
305
+ case error.POSITION_UNAVAILABLE:
306
+ errorMessage = 'Informaci贸n de ubicaci贸n no disponible.';
307
+ break;
308
+ case error.TIMEOUT:
309
+ errorMessage = 'Tiempo de espera para obtener ubicaci贸n agotado.';
310
+ break;
311
+ }
312
+
313
+ locationInfo.textContent = errorMessage;
314
+ showError(errorMessage);
315
+ },
316
+ { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
317
+ );
318
+ } else {
319
+ showError('Geolocalizaci贸n no es soportada por tu navegador.');
320
+ }
321
+ }
322
+
323
+ // Volver a tomar foto
324
+ function retakePhoto() {
325
+ cameraView.classList.remove('hidden');
326
+ photoView.classList.add('hidden');
327
+ generateKmlBtn.classList.add('hidden');
328
+ currentLocation = null;
329
+ photoDataUrl = '';
330
+ photoWithOverlayDataUrl = '';
331
+ startCamera();
332
+ }
333
+
334
+ // Generar y descargar KML con UTM WGS84 Zona 18S
335
+ async function generateKml() {
336
+ if (!currentLocation || !photoDataUrl) {
337
+ showError('No hay foto o ubicaci贸n disponible.');
338
+ return;
339
+ }
340
+
341
+ // Asegurarse de que tenemos la imagen con overlay
342
+ if (!photoWithOverlayDataUrl) {
343
+ await createImageWithOverlay();
344
+ }
345
+
346
+ // Convertir a UTM Zona 18S usando proj4js
347
+ const utm = toUTM(currentLocation.lat, currentLocation.lng);
348
+
349
+ // Crear contenido KML
350
+ const kmlContent = `<?xml version="1.0" encoding="UTF-8"?>
351
+ <kml xmlns="http://www.opengis.net/kml/2.2">
352
+ <Document>
353
+ <name>Obra Q72 Ampliaci贸n Ruta S-839</name>
354
+ <description><![CDATA[
355
+ <h1>OBRA Q72 AMPLIACI脫N RUTA S-839</h1>
356
+ <img src="${photoWithOverlayDataUrl}" width="800" style="display: block; margin: 0 auto;"/>
357
+ <h2>Informaci贸n de la obra</h2>
358
+ <p><strong>Fecha:</strong> ${new Date(photoDateTime).toLocaleString()}</p>
359
+ <p><strong>Coordenadas UTM WGS84 Zona 18S</strong></p>
360
+ <p><strong>Este:</strong> ${utm.easting}</p>
361
+ <p><strong>Norte:</strong> ${utm.northing}</p>
362
+ <p><strong>Altitud:</strong> ${currentLocation.alt.toFixed(2)} metros</p>
363
+ <p><strong>Coordenadas originales WGS84:</strong> ${currentLocation.lat.toFixed(6)}, ${currentLocation.lng.toFixed(6)}</p>
364
+ ]]></description>
365
+ <Placemark>
366
+ <name>Ubicaci贸n exacta UTM WGS84 Zona 18S</name>
367
+ <description><![CDATA[
368
+ <p><strong>Este:</strong> ${utm.easting}</p>
369
+ <p><strong>Norte:</strong> ${utm.northing}</p>
370
+ <p><strong>Zona:</strong> ${utm.zone}${utm.hemisphere}</p>
371
+ ]]></description>
372
+ <Point>
373
+ <coordinates>${currentLocation.lng},${currentLocation.lat},${currentLocation.alt}</coordinates>
374
+ </Point>
375
+ <Style>
376
+ <IconStyle>
377
+ <Icon>
378
+ <href>https://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>
379
+ </Icon>
380
+ <color>ff0000ff</color>
381
+ <scale>1.2</scale>
382
+ </IconStyle>
383
+ </Style>
384
+ </Placemark>
385
+ </Document>
386
+ </kml>`;
387
+
388
+ // Crear y descargar archivo
389
+ const blob = new Blob([kmlContent], { type: 'application/vnd.google-earth.kml+xml' });
390
+ const url = URL.createObjectURL(blob);
391
+ const a = document.createElement('a');
392
+ a.href = url;
393
+ a.download = `Obra_Q72_UTM18S_${new Date(photoDateTime).toISOString().replace(/[:.]/g, '-')}.kml`;
394
+ document.body.appendChild(a);
395
+ a.click();
396
+ document.body.removeChild(a);
397
+ URL.revokeObjectURL(url);
398
+ }
399
+
400
+ // Mostrar error
401
+ function showError(message) {
402
+ errorText.textContent = message;
403
+ errorMsg.classList.remove('hidden');
404
+ setTimeout(() => errorMsg.classList.add('hidden'), 5000);
405
+ }
406
+
407
+ // Event listeners
408
+ captureBtn.addEventListener('click', capturePhoto);
409
+ retakeBtn.addEventListener('click', retakePhoto);
410
+ generateKmlBtn.addEventListener('click', generateKml);
411
+
412
+ // Iniciar la aplicaci贸n
413
+ startCamera();
414
+ </script>
415
+ <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=ignaciomdr/fotokmz" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
416
+ </html>