Llesques de la mateixa altura, igual superfície de crosta

LlesquesImaginem que tenim un pa rodó. Però rodó rodó, esfèric. Si el llesquem amb llesques de 1,5 cm (1 cm massa primes, 2 cm massa gruixudes), la crosta que obtenim de les diferents llesques té la mateixa superfície.
També ho podem pensar en una taronja, que sí que és esfèrica.

La demostració la vaig veure en aquest tweet, tot i que l’explicació i el dibuix no és molt convincent. O sigui que l’he reproduït a la meva manera.

És un exercici d’integració i càlcul de superfície sobre una esfera, de nivell de primer de carrera. El resultat final és que per b-a constants, que és l’altura de la llesca, la superfície és la mateixa: A = 2*Pi*R*(b-a). Sempre s’aprenen coses noves.

El pdf amb la meva solució:

Millorar les fotos del mòbil

Coll de JouEs tracta d’aplicar un fitre com els que trobem a Instagram. Si vull automatitzar-ho, puc fer servir Imagemagick, que és una navalla suïssa per a la transformació d’imatges.

Al final he trobat la pàgina de fmwconcepts.com, que ofereix molts filtres en forma de script. A mi el que m’interessa i que em pot donar molt bon resultat és un filtre que s’anomena levels, que es tracta de modificar (fer un stretch) dels nivells, igual que faríem amb Gimp: Colors > Nivells. Amb el Gimp també em dóna un bon resultat fer Colors > Corbes, i veig que també hi ha el script (filtre) curbes. Per tant, també el podria provar, aquest.

Vull automatitzar el procés de generar imatges millorades de les imatges contingudes en una carpeta. Per tant, el meu script haurà d’anar imatge per imatge (primer bucle). I dins de cada imatge, fer un escombrat de paràmetres, de manera que per cada imatge generem 4 fotos. Finalment, haurem d’escollir quina és la foto que ha quedat millor, que ha quedat més contrastada i amb colors vius.

El script:

RUTA=/home/joan/projectes/OSM/marker_animation/filtre_levels
RUTAPICS=/home/joan/projectes/OSM/marker_animation/res/ribes-taga-ogassa-camprodon-ribes/prov
RUTARESULTATS=/home/joan/projectes/OSM/marker_animation/res/ribes-taga-ogassa-camprodon-ribes/prov/resultats
FILTRE=levels

clear
cd $RUTAPICS

for f in *.jpg
do
	cp $RUTAPICS/$f $RUTARESULTATS
	LEFT=0
	RIGHT=100
	START=0
	i=$START
	echo $f
	name=$(echo "$f" | cut -f 1 -d '.')
	for i in 0 1 2 3
	do
		LEFT=$(($LEFT+5))
		RIGHT=$(($RIGHT-5))
		i=$(($i+1))
		your_options="-C global -i $LEFT,$RIGHT $RUTAPICS/$f $RUTARESULTATS/$name-$i.jpg"
		FILTREAMBOPCIONS="levels $your_options"
		$RUTA/$FILTREAMBOPCIONS

	done
done

Més informació:

Curs MOOC ABP-2. Unitat 4: Fitxa de Projecte

Fitxa de projecteArribem ja a la Unitat 4 (i darrera) del curs MOOC-ABP2 d’Aprenenatge Basat en Projectes. Aquesta setmana ens ha tocat fer la fitxa d’un dels projectes que vam pensar la setmana passada. Farem la fitxa del Projecte Trescant, on es tracta de fer una pàgina web d’excursions (a peu, amb bicicleta), i que aquesta web tingui els següents requisits:

  • S’ha de visualitzar el track de l’excursió sobre un mapa
  • Ha de ser interactiu i dinàmic: hem de veure com es mou el punter sobre el track
  • Van apareixent fotografies i textos a mida que avança l’excursió
  • S’utilitzarà la llibreria Openlayers

Un exemple de resultat es pot veure en aquest enllaç.

L’avaluació del projecte ha de ser competencial. El que hem treballat aquesta setmana és dividir el projecte en AEA (Activitats d’Ensenyament-Aprenentatge) i veure quins RA (Resultats d’Aprenentatge) s’han d’assolir en la UF on està ubicat el projecte. Hem de dissenyar el projecte i les AEA de manera que es vegin tots els RA que hem d’avaluar. Aleshores fem una graella/llençol on quedin constància les AEA amb els seus RA. A més, hem de tenir columnes per als Criteris d’Avaluació (CA), de manera que un RA l’avaluarem mitjançant CA, i hem d’assignar pesos.

Els criteris d’avaluació que farem servir són l’observació a l’aula, el treball individual, el producte assolit, l’exposició, la difusió, la coavaluació. De manera que anem registrant tota aquesta informació, i podrem veure si un RA està assolit o no, si el AEA està assolit o no. Al final de tot haurem de tenir una nota de la UF. La nota de la UF pot venir només del Projecte, o potser hem fet també un examen o una pràctica individual.

Sembla molt complicat, però al final és tenir clar que l’avaluació és competencial i que hem de tenir quins són els Resultats d’Aprenentatge que s’han d’assolir.

Pots descarregar aquí el pdf de la meva fitxa de projecte:

El nom Gal·la i la validació de formularis

validació formulari amb punt volatHe vist en el twitter una noia que té problemes per demanar un certificat, perquè es diu Gal·la i la validació del formulari no accepta noms amb punt volat. Això no és nou, he vist aquesta notícia d’una cas semblant que ja passava el 2004.

Tècnicament no és cap problema, només cal incloure el punt volat en l’expressió regular per validar el nom, per exemple:

> let patt = /^[a-z\u00C0-\u017F, .·'-]+$/i;
> let nom = 'Gal·la';
> console.log(patt.test(nom));
true

I és que tenim un estat al darrera que no contempla la possibilitat de què hi ha gent que vol viure plenament en català, a tot arreu, a tota hora i amb tothom. Altres noms que es poden trobar en la mateixa situacuió: Gal·la, Gal·lo, Marcel·la, Marcel·lí, Avel·lí, Estel·la, Apel·les, Marcel·lí i Sibil·la. I com a cognom he trobat Al·lès. El nom de Gal·lo, tot i que estrany, a mi m’és familiar perquè un germà del meu avi se’n deia, tot i que no crec que l’hagués escrit mai amb ela geminada, si bé la pronúncia segur que era exquisida.

Curs MOOC ABP-2. Unitat 3: Productes finals

Productes finals
Entrem a la unitat 3 del curs MOOC-ABP2, i tracta de la Guia per la programació ABP. Els projectes ABP s’han de programar, tenint en compte les RA, CA i continguts del mòdul en el qual es fa el projecte. De les diferents possibilitats que hi ha, nosaltres triem fer un projecte que estigui circunscrit en només un mòdul professional: el mòdul M06 de DAW, que és programació web en entorn de client, és a dir, Javascript.

Avui dia amb Javascript (el que ve a anomenar-se desenvolupament front-end) es poden obtenir uns resultas espectaculars (disseny, interacció, experiència d’usuari,…). I els projectes que volem realitzar a classe volen ser un reflexe de les possibilitats que ofereix el Javascript modern. És la manera d’enganxar els alumnes, fent projectes engrescadors.

En el pdf es pot veure una mostra, un llençol, dels diferents projectes que es poden fer a l’aula. No és possible fer tots aquests projectes en un curs. Es tracta de seleccionar-ne dos, i l’any següent fer-ne dos més, i així rotar, i potser repetir algun projecte que hagi sortit molt bé. D’aquesta manera anem construint un portfoli de projectes que hem anat realitzant.

Curs MOOC ABP-2. Unitat 2: instruments d’avaluació

Instruments avaluació
Ja som a la setmana 2, la unitat 2, i aquesta vegada toca reflexionar sobre els instruments d’avaluació per tal d’avaluar el projecte plantejat. Al final de tot haurem de treure una nota numèrica, que és el que ens demana la casella del mòdul de Projecte del SAGA. Ara bé, la nota numèrica serà al final menys important: l’avaluació és formativa, l’alumne participa del procés d’avaluació, l’alumne és conscient dels seus progressos, l’alumne pren consciència del seu procés d’aprenentatge. Al final els professors acumulem molta informació, i el fet de posar una nota numèrica és el de menys.

Pots descarregar la infografia dels instruments d’avaluació dissenyats per aquest projecte. Això és tan sols la infografia, tot el detall de les rúbriques d’avaluació és molt més llarg i aniria en una documentació apart.

Curs MOOC ABP-2 (tardor 2022)

Portada organitzadorEl curs passat vam fer el MOOC-1, i aquí estem de nou fent el MOOC-2. En aquesta primera unitat hem de lliurar els organitzadors d’un hipotètic projecte. Com a projecte jo escullo realitzar una pàgina web per a una entitat excursionista. L’objectiu de la web és visualitzar de forma dinàmica i interactiva una excursió, amb explicacions i fotos, de manera que tot plegat ha de ser una experiència visualment rica.
L’organitzador és la primera etapa del plantejament del projecte ABP, i ens hem de posar en el punt de vista de l’alumne, de l’equip de l’alumne, de l’equip docent, de l’entitat col·laboradora (el club excursionista), el col·lectiu final (els excursionistes), i el context docent (l’institut, AMPA).

Aquí va la meva proposta per descarregar i en format pdf:

Simular el posicionament GPS (problemes en el desplegament al núvol, OVH)

Tenim una REST API amb MongoDB. Tenim un front-end per generar posicions i gravar-les a la bd. I tenim un altre front-end per visualitzar les posicions i veure com van evolucionant.

La part de generar les posicions i enviar-les al servidor de moment no és una aplicació mòbil, sinó que és una pàgina web. Openlayers té la possibilitat de fer geolocation, i per tant tenim una precisió molt bona (uns 15 m). No cal per tant una aplicació mòbil. Ara bé, s’ha de fer amb 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.

Fins aquí cap problema quan es desenvolupa localment (localhost). Però el problema està quan es desplega al servidor, en aquest cas un VPS a OVH. Per tant, la part de generar les posicions GPS ha d’anar al servidor OVH on hi ha instal·lat el certificat SSL. Ara bé, no es poden generar certificats per al domini ovh.net (es denega perquè s’han passat de la quota, lògic). Així doncs, primer m’he hagut de registrar a noip.com i ara tinc el domini jquintana.ddns.net.

Posar el MongoDB al servidor no ha tingut cap problema. El problema està en la API REST, feta amb Express. La API REST s’ha hagut de fer segura (https), doncs no podia ser que cridéssim a la API des de https, i que aquest servidor respongués amb http. Aquest ha sigut el problema principal.

Finalment la part del front-end de visualitzar les posicions no ha tingut especial problema. Les crides a la API http://localhost:3000 s’han de canviar a les crides a la API https://jquintana.ddns.net:8080.

En resum, tu pots tenir una aplicació funcionant amb localhost sense especials problemes, i quan la vols desplegar al núvol comencen els problemes de CORS, seguretat, protocols que no t’havies plantejat.

Ara l’últim pas és tenir un codi que funcioni igual de bé a localhost i al núvol, que això en principi no serà problema. I la reflexió és que quan desenvolupes un projecte, no s’ha d’esperar al final de tot a desplegar-lo a la infraestructura del núvol. S’ha de fer ja en les primeres fases: és el desplegament continu. Encara que l’aplicació no tingui moltes funcionalitats, ja s’ha pogut afrontar tots els problemes de seguretat i infraestructura al provar de desplegar-ho en l’entorn real en les primeres fases. I així ens estalviem problemes al final del projecte.

Programant el tracking de rutes

Exemple canònic OpenlayersAhir al vespre estava programant, i estava gravant posicions simulades des de casa. Com a casa no em moc, vaig simular un cert moviment. Les dades es graven en una base de dades MongoDB.

Avui estava continuant una mica, des de l’institut, i voilà, hi ha un salt de casa a l’institut. Lògic però divertit.

Openlayers: Point, LineString, MultiLineString, Icon. Exemple canònic

Exemple canònic OpenlayersAnem a mostrar un exemple mínim d’Openlauers que aclareixi els conceptes de dibuixar un punt, una línia, una multilínia i una icona. I com aplicar estils a aquests elements.

Definim primer aquests elements (punts, línies, multilínies, icones) a partir de les dades d’exemple (coordenades). Aleshores definim features a partir d’aquests elements, que afegim a un array de features. Cada feature pot tenir el seu estil.

Definim després el vectorSource a partir de l’array de features. Després definim el VectorLayer a partir del vectorSource. I finalment afegim al mapa els layers que volem pintar.

Aquest és el codi inicial i previ per a un petit projecte que vull fer, que tracta d’una aplicació mòbil per enviar les coordenades de posició a una RestAPI on hi ha una base de dades (MongoDB), i amb una aplicació web (front-end, que és la part que aquí es comença a explicar) poder visualitzar el recorregut del ciclista (la idea del projecte és poder fer el tracking d’un ciclista en una primera etapa; i en una etapa posterior poder fer el tracking de tots els ciclistes que participen en una cursa o sortida).

El codi 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
})
});