Rebanadas de la misma altura, igual superficie de costra

LlesquesImaginemos que tenemos un pa redondo. Pero redondo esférico. Si hacemos rebanadas de 1,5 cm (1 cm demasiado delgadas, 2 cm demasiado gruesas), la costra que obtenemos de las diferentes rebanadas tiene la misma superficie.
También lo podemos pensar para una naranja, que sí que es esférica.

La demostración la vi en este tweet, aunque la explicación y el dibujo no son muy convincentes. O sea que lo he reproducido a mi manera.

Es un ejercicio de integración y cálculo de superficie sobre una esfera, de nivel de primero de carrera. El resultado final es que para b-a constantes, que es la altura de la rebanada, la superficie es la misma: A = 2*Pi*R*(b-a). Siempre se aprenden cosas nuevas.

El pdf con mi solución:

Simular el posicionamient GPS (problemas en el despliegue a la nube, OVH)

Tenemos una REST API con MongoDB. Tenemos un front-end para generar posiciones y grabarlas en la bd. Y tenemos otro front-end para visualizar las posiciones y ver cómo van evolucionando.

La parte de generar las posiciones y enviarlas al servidor de momento no es una aplicación móvil, sino que es una página web. Openlayers tiene la posibilidad de hacer geolocation, y por tanto tenemos una precisión muy buena (unos 15 m). No es necesario por tanto una aplicación móvil. Ahora bien, hay que hacerlo con https.

(ref): https://stackoverflow.com/questions/39366758/geolocation-without-ssl-connection:

Warning by Chrome : getCurrentPosition() and watchPosition() no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS.

Hasta aquí ningún problema especial cuando se desarrolla localmente (localhost). Pero el problema esté cuando se despliega en el servidor, en este caso un VPS en OVH. Por tanto, la parte de generar las posiciones GPS tiene que ir al servidor OVH donde hay instalado el certificado SSL. Ahora bien, no se pueden generar certificados para el dominio ovh.net con noip.com (se han pasado de la cuota, lógico). Así pues, primero me he tenido que registrar en noip.com y ahora tengo el dominio jquintana.ddns.net.

Poner el MongoDB en el servidor no ha sido ningún problema. El problema está en la API REST, hecha con Express. La API REST se ha tenido que hacer segura (https), pues no podía ser que llamásemos a la API desde https, y que este servidor respondiese com http. Este ha sido el problema principal.

Finalmente la parte del front-end de visualizar las posiciones no ha tenido especial problema. Las llamadas a la API http://localhost:3000 se han de cambiar a les llamadas a la API https://jquintana.ddns.net:8080.

En resumen, tú puedes tener una aplicación funcionando con localhost sin especiales problemas, y cuando la quieres desplegar en la nube empiezan los problemas de CORS, seguridad, protocolos que no te habías planteado.

Ahora el último paso es tener un código que funcione igual de bien en localhost y en la nube, que esto en principio no será problema. Y la reflexión es que cuando se desarrolla un proyecto, no hay que esperar al final de tot para desplegarlo a la infraestructura de la nube. Hay que hacerlo ya en las primeras fases: es el despliegue continuo. Aunque la aplicación no tenga muchas funcionalidades, ya se ha podido afrontar todos los problemas de seguridad e infraestructura al intentar desplegar en un entorno real en las primeras fases. Y así nos ahorramos problemas al final del proyecto.

Programando el tracking de rutas

Programando casa-insitutoAyer por la noche estaba programando, y estaba grabando posiciones simuladas desde casa. Como en casa no me muevo, tuve que simular cierto movimiento. Los datos se graban en una base de datos MongoDB.

Hoy estaba continuando un rato, desde el instituto, y voilà, hay un salto desce casa al instituto. Lógico pero divertido.

Openlayers: Point, LineString, MultiLineString, Icon. Ejemplo canónico

Ejemplo canónico OpenlayersVamos a mostrar un ejemplo mínimo de Openlayers que aclare los conceptos de dibujar un punto, una línea, una multilínea y un icono. Y cómo aplicar estilos a estos elementos.

Definimos primero estos elementos (puntos, líneas, multilíneas, iconos) a partir de los datos de ejemplo (coordenadas). Entonces definimos features a partir de estos elementos, que aañadimos a un array de features. Cada feature puede tener su estilo.

Definimos después el vectorSource a partir del array de features. Después definimos el VectorLayer a partir del vectorSource. Y finalmente añadimos al mapa los layers que queremos pintar.

Este es el codi inicial y previo para un pequeño proyecto que quiero hacer, que se trata de una aplicación mòvil para enviar las coordenadas de posición a una RestAPI donde hay una base de datos (MongoDB), y con una aplicación web (front-end, que es la part que aquí se empieza a explicar) poder visualizar el recorrido del ciclista (la idea del proyecto es poder hacer el tracking de un ciclista en una primera etapa; y en una etapa posterior poder hacer el tracking de todos los ciclistas que participan en una carrera o salida).

El código final:

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Icon, Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style';
import {LineString, MultiLineString, Point} from 'ol/geom';
import {getVectorContext} from 'ol/render';
import {fromLonLat} from 'ol/proj';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import OSM from 'ol/source/OSM';

//dades
var json_points = [
{'lon':1.4234,'lat':41.2344,'name':'punt 0'},
{'lon':1.4235,'lat':41.2345,'name':'punt 1'},
{'lon':1.4235,'lat':41.2346,'name':'punt 2'},
{'lon':1.4236,'lat':41.2346,'name':'punt 3'},
{'lon':1.4236,'lat':41.2347,'name':'punt 4'},
{'lon':1.4238,'lat':41.2349,'name':'punt 4'},
{'lon':1.4239,'lat':41.2350,'name':'punt 4'}
];

// estils
var styles = {
'Point': new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(100,100,100,.8)',
}),
radius: 3,
stroke: new Stroke({
color: '#000000',
width: 2,
}),
}),
}),
'LineString': new Style({
stroke: new Stroke({
color: '#f00',
width: 3,
}),
}),
'MultiLineString': new Style({
stroke: new Stroke({
color: '#000000',
width: .8,
}),
}),
'icona': new Style({
image: new Icon({
anchor: [0.5,20],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'img/circle_red_8.png'
})
})
};

// points
var features_points = new Array();

var feature_point0 = new Feature({
'geometry': new Point(fromLonLat([json_points[0].lon,json_points[0].lat])),
'name': json_points[0].name,
});

var feature_point1 = new Feature({
'geometry': new Point(fromLonLat([json_points[1].lon,json_points[1].lat])),
'name': json_points[0].name,
});

var feature_point2 = new Feature({
'geometry': new Point(fromLonLat([json_points[2].lon,json_points[2].lat])),
'name': json_points[0].name,
});

var feature_point3 = new Feature({
'geometry': new Point(fromLonLat([json_points[3].lon,json_points[3].lat])),
'name': json_points[0].name,
});

var feature_point4 = new Feature({
'geometry': new Point(fromLonLat([json_points[4].lon,json_points[4].lat])),
'name': json_points[0].name,
});

features_points.push(feature_point0)
features_points.push(feature_point1)
features_points.push(feature_point2)
features_points.push(feature_point3)
features_points.push(feature_point4)

// línies
//Create a feature and add geometry as a thing
var track1 = new MultiLineString([
[[json_points[0].lon,json_points[0].lat],[json_points[1].lon,json_points[1].lat]],
[[json_points[1].lon,json_points[1].lat],[json_points[2].lon,json_points[2].lat]],
[[json_points[2].lon,json_points[2].lat],[json_points[3].lon,json_points[3].lat]],
[[json_points[3].lon,json_points[3].lat],[json_points[4].lon,json_points[4].lat]]
]).transform('EPSG:4326','EPSG:3857');

var feature_multilinestring = new Feature({
geometry: track1,
name: 'nom track 1'
});

var line1 = new LineString([
[json_points[5].lon,json_points[5].lat],[json_points[6].lon,json_points[6].lat]
]).transform('EPSG:4326','EPSG:3857');

var feature_linestring = new Feature({
geometry: line1,
name: 'nom línia 1'
});

var features_strings = new Array();

features_strings.push(feature_multilinestring)
features_strings.push(feature_linestring)

//icones
var features_icones = new Array();

let feature_icona1 = new Feature({
geometry: new Point(fromLonLat([json_points[5].lon,json_points[5].lat])),
name: 'Inici',
});

let feature_icona2 = new Feature({
geometry: new Point(fromLonLat([json_points[6].lon,json_points[6].lat])),
name: 'Final',
});

feature_icona1.setStyle(styles.icona); //no cal si defineixo el estil en el layer.
feature_icona2.setStyle(styles.icona); //però definiré l'estil en la icona si cada icona ha de tenir un estil diferent

features_icones.push(feature_icona1);
features_icones.push(feature_icona2);

// vectorSources
var vectorSourcePoints = new VectorSource({
features: features_points,
wrapX: false,
});

var vectorSourceStrings = new VectorSource({
features: features_strings,
wrapX: false,
});

var vectorSourceIcones = new VectorSource({
features: features_icones,
wrapX: false,
});

// layers
var layerPoints = new VectorLayer({
source: vectorSourcePoints,
style: styles.Point,
});

var layerStrings = new VectorLayer({
source: vectorSourceStrings,
style: styles.MultiLineString,
});

var layerIcones = new VectorLayer({
source: vectorSourceIcones,
style: styles.icona,
});

var map = new Map({
layers: [
new TileLayer({
source: new OSM({
layer: 'OSM'
})
}),
layerPoints,
layerStrings,
layerIcones
],
target: 'map',
view: new View({
center: fromLonLat([1.4234, 41.2344]),
zoom: 18
})
});

MOOC-ABP. Diario de aprendizaje

Joan QuintanaEste es mi blog que utilizo desde el año 2009, y en la categoría MOOC-ABP iré construyendo el diario de aprendizaje de este curso online de metodologías activas. De momento aquí va mi presentación, i todo lo que esté relacionado con este curso irá en la categoría de MOOC ABP.

Trabajo en INS Jaume Balmes de Barcelona como profesor dels ciclos de Desarrollo de Aplicacions Web (DAW) y Desarrollo de Aplicaciones Multiplataforma (DAM), y mis ámbitos preferidos son el desarrollo Full Stack y bases de datos.

Referencias:

Idea para una camiseta

Esta mañana estaba estudiando las funciones flecha de Javascript. Y ahora se me ha ocurrido esta idea.

BDQuest: Quests para el lenguaje SQL

Este año hago en 1º de DAM la M02, Bases de Datos. Siempre he trabajado con bases de datos, con los alumnos, pero esta asignatura hacía mucho tiempo que no la hacía.

En verano me animé a hacer una herramienta web para que los alumnos pudiesen testear sus sentencias SQL de forma automática, y que también fuese un recurso para evaluar y auto-evaluar. Esta aplicación es BDQuest, el nombre no es muy original, pero a estas alturas ya no me atrevo a cambiarlo.

Empezamos el curso y en la UF1 no se hace nada de SQL. Pero en la UF2, que es la troncal del curso y que ya estamos acabando, los alumnos han estado utilizando la herramienta, y así poder practicar selects básicas, inserts, updates, deletes, create, alter y drop tables, create y drop views, selects complejas, etc.

Los alumnos han hecho de conejitos de indies y la versión 10, que es la actual, la he ido actualizando a lo largo del trimestre. ¡Y funciona muy bien!

Y ahora que estamos acabando la UF2 y no falta nada para empezar la UF3, he adaptado la aplicación para poder hacer create y drop users, grant privilegios, etc; y también create procedures, etc. Y los triggers ya vendrán. Es decir, que el objetivo inicial de que no sólo sirviese para hacer selects se habrá cumplido de sobras.

Hasta ahora no había escrito nada ni aquí ni en la wiki. Ya es hora de documentar un poco el proyecto y darlo a conocer. A ver si alguien le puede sacar provecho.

A la aplicación todavía le faltan muchas cosas, pero lo importante es que este año ha sido funcional. Es una típica aplicación web con mucho de Javascript y PHP-MySQL, y con un diseño de momento minimalista. La aplicación tendría que crecer por aquí: mejorar el diseño; y utilitzar algún framework en el lado del cliente y del servidor. Y también alguna refactoritzación del código y mejora de unas cuantas cosas.

CatGeoQuest: aplicación para hacer tests de geografía

En esto estoy estos últimos días. Me he dado prisa para poder hacer una demo que se pueda enseñar y que ya sea jugable.

Tengo muchas ideas relacionadas con esta aplicación, puede crecer bastante. Lo que todavía no tengo claro es si le pondré una capa de back-end con bases de datos, o lo dejaré como una SPA (Single Page Application) con sólo front-end y Javascript.

He intentado sacar el máximo provecho de la librería de Openlayers y, como siempre, me ha dado algún quebradero de cabeza pero también he aprendido bastante por el camino. Ahora que ya tengo una versión jugable, el camino para continuar será más plácido y tranquilo…

Paraulògic

Hace días que todo el mundo por aquí Catalunya va detrás de esta aplicación del Paraulògic, para encontrar palabras en catalán que están en el diccionario DIEC (el diccionario del Institut d’Estudis Catalans.

A partir de un tweet de hoy se ha puesto en evidencia la sencillez de la aplicación web, todas las palabras del día están en el código html y en texto plano. Pensaba que la aplicación se conectaría a alguna API del diccionario del DIEC (sería muy interesante que existiese esta API y que fuese de acceso libre).
Però no, la cosa es mucho más sencilla: todas las palabras del día se pueden ver haciendo el típico Ctrl-U (Ver código fuente), y allá tienes todas las palabras sin codificar, y de esta manera es muy sencillo tener la máxima puntuación y poderte lucir delante de la gente y de los familiares. Lo que se puede hacer para evitarlo es una encriptación fácil con Base64, almenos para ponerlo un poco más difícil a los curiosos del html.

Lástima que las vacaciones de Navidad ya se han acabado y ya no podremos dedicar más tiempo a esto del Paraulògic

Geometría para acabar el año

Para acabar el año, el reto de hacer y entender una demostración de geometría.

El problema: dado un polígono regular de N lados (por ejemplo un heptágono como el de la figura), demostrar que los ángulos que forman las diagonales que salen de un vértice, tienen todos estos ángulos el mismo valor, y decir qué valor tiene.

La demostración del reto está en el pdf de abajo. No es una demostración evidente, es un de aquellos casos en que el enunciado es muy fácil, piensas que la demostración será rápida y fácil, y después no lo es. En este caso, he tenido que profundizar en los cuadriláteros inscritos en una circunferencia (que también se llaman cíclicos), y sus propiedades: concretamente, en un polígono inscrit los ángulos opuestos son suplementarios (suman 180º).

Para hacer la demostración es necesaria una cadena de resultados y demostraciones previas, algunas evidentes, i otras no tanto.

Feliz año 2022 y muchas matemáticas para el nuevo año!

La demostración: demostración de que en un polígono regular las diagonales que parten de un vértice tienen el mismo ángulo: 180/N.