//Projet conçu et réalisé par Charlotte Gauvin & Maxime Foisseau,2012.
//À l’initiative d’un workshop avec Lionel Maes, à La Cambre, Bruxelles, 2011.
//Form & Type de Gauvin Charlotte et Foisseau Maxime est mis à disposition selon les termes de la licence Creative Commons Attribution
//- Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
//Les autorisations au-delà du champ de cette licence peuvent être obtenues à foisseau_max@hotmail.com
import processing.pdf.*;
boolean doSave = false;
import geomerative.*;
RFont font;
RFont font2;
PImage titre;
Textlabel myTextlabelA;
int taille = 100;
int afficheMode = 1;
Letter[] letters;
int nbLetters = 0;
int borderLeft=60;
int borderTop=260;
//marges de bordures
float posX = borderLeft;
float posY = taille+30;
int shapeSet = 0;
//pour charger les svg
PShape module1, module2;
import controlP5.*;
ControlP5 controlP5;
controlP5.Label label;
ControlWindow controlWindow;
public int couleur_R1 = 40;
public int couleur_V1 = 40;
public int couleur_B1 = 40;
public int alpha1 = 100;
public int couleur_R2 = 40;
public int couleur_V2 = 40;
public int couleur_B2 = 40;
public int alpha2 = 100;
boolean mode_forme = true;
boolean exportation = true;
void setup() {
size(screen.width*3/4-150,screen.height);
// fenetre avec redimension
frame.setResizable(true);
String helps[] = {"Form & Type est une interface composée de deux espaces:\n\n◊ un espace d’écriture où le texte \nest composé de deux polices \nde caractères superposées, \nla Cochin et la Akzident Grotesk.\n\n◊ un espace de paramètres graphique \noù il est possible de gérer plusieurs \nvariables telles que choisir la \ncouleur de chaque police de caractères, \nen pourcentage RVB, l’opacité ou encore \nla taille.\n\n◊ le bouton «Mode Forme» permet de passer \ndu dessin de caractère original à une \napplication de formes sur les contours \nde la lettre. Plusieurs formes sont \ndisponibles, il suffit d'appuyer sur \nla touche «Alt» pour les faire défiler.","\n\n◊ le déplacement vertical de la \nsouris dans l’espace d’écriture \npermet le grossissement des formes \net le déplacement horizontal \npermet la rotations des formes \nsur elles-mêmes.\n\n◊ le bouton «Exportation» permet \nde générer la typographie créée\nau format PDF (capture écran de \nl’espace d’écriture), touche «Ctrl».","Projet conçu et réalisé par Charlotte Gauvin & Maxime Foisseau,2012.\nà l’initiative d’un workshop avec Lionel Maes, à La Cambre, Bruxelles, 2011."};
titre = loadImage("logo_form_type.png");
//lisse les formes
smooth();
//chargement de la forme des modules de bases
module1 = loadShape("A_01.svg");
module2 = loadShape("A_02.svg");
//desactivation des données de formes
module1.disableStyle();
module2.disableStyle();
// initialiser la bibliothèque
RG.init(this);
//ajoute enlève des points
//RCommand.setSegmentStep(10);
//RCommand.setSegmentator(RCommand.UNIFORMSTEP);
RCommand.setSegmentLength(6);
RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
//RCommand.setSegmentAngle(random(0,HALF_PI));
//RCommand.setSegmentator(RCommand.ADAPTATIVE);
controlP5 = new ControlP5(this);
PFont p = createFont("NotCourierSans.ttf",10,true);
controlP5.setControlFont(p);
controlP5.setAutoDraw(false);
controlWindow = controlP5.addControlWindow("controlP5window",screen.width*3/4+150,0,screen.width*1/4+150,height);
controlWindow.hideCoordinates();
myTextlabelA = controlP5.addTextlabel("label8","Paramètres Cochin",40,280);
myTextlabelA.setWindow(controlWindow);
controlWindow.setBackground(color(40));
Controller sprite = controlP5.addButton("rewindButton",0,0,0,0,0);
sprite.setImages(loadImage("logo_form_type.png"),loadImage("logo_form_type.png"),loadImage("logo_form_type.png"),loadImage("logo_form_type.png"));
sprite.setWindow(controlWindow);
Controller mySlider = controlP5.addSlider("couleur_R1",0,255,40,310,100,10);
mySlider.setWindow(controlWindow);
Controller mySlider2 = controlP5.addSlider("couleur_V1",0,255,40,330,100,10);
mySlider2.setWindow(controlWindow);
Controller mySlider3 = controlP5.addSlider("couleur_B1",0,255,40,350,100,10);
mySlider3.setWindow(controlWindow);
Controller mySlideralpha = controlP5.addSlider("alpha1",0,255,40,370,100,10);
mySlideralpha.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label","Paramètres Akzidenz Grotesk",250,280);
myTextlabelA.setWindow(controlWindow);
Controller mySliderbis = controlP5.addSlider("couleur_R2",0,255,250,310,100,10);
mySliderbis.setWindow(controlWindow);
Controller mySliderbis2 = controlP5.addSlider("couleur_V2",0,255,250,330,100,10);
mySliderbis2.setWindow(controlWindow);
Controller mySliderbis3 = controlP5.addSlider("couleur_B2",0,255,250,350,100,10);
mySliderbis3.setWindow(controlWindow);
Controller mySlideralpha2 = controlP5.addSlider("alpha2",0,255,250,370,100,10);
mySlideralpha2.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label1"," Paramètres général",40,410);
myTextlabelA.setWindow(controlWindow);
Controller mySlidertaille = controlP5.addSlider("taille",100,255,40,440,340,10);
mySlidertaille.setWindow(controlWindow);
Controller myButton =controlP5.addToggle("mode_forme",false,40,470,60,19);
myButton.setWindow(controlWindow);
Controller myButton2 =controlP5.addButton("exportation",0,170,470,90,19);
myButton2.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label2"," Mode d'emploi",40,550);
myTextlabelA.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label3",helps[0],15,570);
myTextlabelA.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label3",helps[1],285,570);
myTextlabelA.setWindow(controlWindow);
myTextlabelA = controlP5.addTextlabel("label4",helps[2],20,screen.height-80);
myTextlabelA.setWindow(controlWindow);
controlWindow.setTitle("Paramètres graphiques");
//////////on initialise le tableau letters qui contiendra chaque lettre
letters = new Letter[10000];
}
void draw() {
frame.setLocation(0,0);
// charger la police
font = new RFont("COCHIN.TTF", int (taille/(0.8)), RFont.LEFT);
font2 = new RFont("AkzidenzGrotesk-Roman.ttf", taille, RFont.LEFT);
//sauvegarde mode pdf
background(255);
noStroke();
shapeMode(CENTER);
controlP5.draw();
for (int i=0; i < nbLetters; i++ ) {
letters[i].affiche();
}
if (doSave) {
beginRecord(PDF, timestamp()+".pdf");
doSave = false;
endRecord();
saveFrame(timestamp()+".pdf");
}
}
void mode_forme(boolean theFlag) {
if(theFlag==true) {
afficheMode=0;
} else {
afficheMode=1;
}
}
public void exportation (int theValue) {
doSave = true;
}
void keyReleased() {
if (keyCode == CONTROL) doSave = true;
}
void keyPressed() {
if(keyCode == UP){
controlP5.window("controlP5window").hide();
}
if(keyCode == DOWN){
controlP5.window("controlP5window").show();
}
if (key != CODED) {
switch(key) {
case '1':
case DELETE:
case BACKSPACE:
posX =letters[nbLetters-2].x;
posY =letters[nbLetters-2].y;
nbLetters-=2;
break;
case TAB:
case ENTER:
posY +=taille+40;
posX =borderLeft;
break;
case RETURN:
case ESC:
case ' ': posX+=taille-68;
break;
default:
/*if(letters.length-1 < nbLetters+2){
letters = expand(letters, 10);
}*/
letters[nbLetters] = new Letter(posX, posY, str(key), true);
letters[nbLetters+1] = new Letter(posX, posY, str(key), false);
if(letters[nbLetters].w < letters[nbLetters+1].w){
letters[nbLetters].x+=(letters[nbLetters+1].w-letters[nbLetters].w)/2;
posX+=letters[nbLetters+1].w+5;
}else{posX+=letters[nbLetters].w+5;
letters[nbLetters+1].x+=(letters[nbLetters].w-letters[nbLetters+1].w)/2;}
nbLetters += 2;
}
}
//switcher les formes
if (keyCode == ALT) {
shapeSet = (shapeSet+1) % 5;
switch(shapeSet) {
case 0:
module1 = loadShape("A_01.svg");
module2 = loadShape("A_02.svg");
break;
case 1:
module1 = loadShape("B_01.svg");
module2 = loadShape("B_01.svg");
break;
case 2:
module1 = loadShape("C_02.svg");
module2 = loadShape("C_02.svg");
break;
case 3:
module1 = loadShape("D_02.svg");
module2 = loadShape("D_02.svg");
break;
case 4:
module1 = loadShape("A_02.svg");
module2 = loadShape("A_02.svg");
break;
}
module1.disableStyle();
module2.disableStyle();
}
}
// enregistrer
String timestamp() {
Calendar now = Calendar.getInstance();
return String.format("%1$ty%1$tm%1$td_%1$tH%1$tM%1$tS", now);
}
class Letter{
float w;
float h;
float x;
float y;
boolean type;
RFont currentFont;
RPoint[][] pointsContour;
RGroup group;
char letter;
Letter(float x, float y, String letter, boolean type){
this.x = x;
this.y = y;
if(type==true){
this.currentFont = font;
}else{
this.currentFont = font2;
}
this.type = type;
group = currentFont.toGroup(letter);
w = group.getWidth();
h = group.getHeight();
pointsContour = group.getPointsInPaths();
float decalage = w;
for (int i=0; i < pointsContour.length; i++ ) {
for (int j=0; j < pointsContour[i].length-1;j++ ) {
if(pointsContour[i][j].x < decalage){
decalage = pointsContour[i][j].x;
}
}
}
for (int i=0; i < pointsContour.length; i++ ) {
for (int j=0; j < pointsContour[i].length-1;j++ ) {
pointsContour[i][j].x -= decalage;
}
}
//print("letter "+letter+" x="+x+" y="+y+" w="+w+" h="+h+"\n");
}
void affiche (){
if(afficheMode == 0){
afficheFormes();
}else if(afficheMode == 1){
afficheTypo();
}
}
void afficheTypo(){
if(type == true){
//SI TYPO 1
//telle couleur telle fonte telle forme, etc.
fill(couleur_R1, couleur_V1, couleur_B1, alpha1);
}else{
fill(couleur_R2, couleur_V2, couleur_B2, alpha2);
}
//rect(x, y, w, h);
for (int i=0; i < pointsContour.length; i++ ) {
beginShape();
for (int j=0; j < pointsContour[i].length-1;j++ ) {
vertex(pointsContour[i][j].x+x, pointsContour[i][j].y+y);
}
endShape();
}
}
void afficheFormes(){
if(type == true){
//SI TYPO 1
//telle couleur telle fonte telle forme, etc.
fill(couleur_R1, couleur_V1, couleur_B1, alpha1);
}else{
fill(couleur_R2, couleur_V2, couleur_B2, alpha2);
}
//taille du diametre
float diameter = 18;
for (int i=0; i < pointsContour.length; i++ ) {
for (int j=0; j < pointsContour[i].length-1;j++ ) {
// sur chaque troisième point
if (j%2 == 0) {
// faites pivoter le module (i +1)
pushMatrix();
float angle = atan2(pointsContour[i][j].y-pointsContour[i][j+1].y, pointsContour[i][j].x-pointsContour[i][j+1].x);
translate(pointsContour[i][j].x+x, pointsContour[i][j].y+y);
rotate(angle);
rotate(radians(-mouseX));
shape(module1, 0,0, diameter+(mouseY/2.5),diameter+(mouseY/2.5));
popMatrix();
}
}
}
}
}
Ce projet est né lors d’un atelier qui s’est tenu en avril 2011 à La Cambre. Animé durant trois jours par le designer graphique Lionel Maes du studio La Villa Hermosa, il portait sur le langage et interface de programmation open-source Processing. Nous avons élaboré un dispositif porté par l’idée de mesurer la variation de lisibilité grâce à la programmation et permettre, sur la base de deux caractères existants (Akzidenz Grotesk roman, et Cochin roman), de créer un nouveau dessin de lettre.