<?php
/******************************************************************************!
* \file gramps2tex.php
* \author Sebastien Beaugrand
* \sa http://beaugrand.chez.com/
* \copyright CeCILL 2.1 Free Software license
******************************************************************************/
if ($argc != 2 || $argv[1] != 'tests') {
if ($argc != 6) {
print "Usage: $argv[0] <export.csv> <1|2> <lmax>";
print " <sibiling-distance> <level-distance>\n";
exit(1);
}
$filename = $argv[1];
$parent = $argv[2];
$lmax = $argv[3];
$below = $argv[4] / 4;
$left = $argv[5] / 2 + 2;
$right = $argv[5] / 2 - 5;
}
const GENRE_M = 1;
const GENRE_F = 2;
const LIEU = 1;
const INDIVIDU = 2;
const MARIAGE = 3;
const FAMILLE = 4;
if (! function_exists('array_key_first')) {
function array_key_first(array $arr) {
foreach ($arr as $key => $unused) {
return $key;
}
return NULL;
}
}
require 'randomColor.php';
/******************************************************************************!
* \class Departement
******************************************************************************/
class Departement
{
var $name;
var $color;
/**************************************************************************!
* \fn construct
**************************************************************************/
function __construct($d) {
$this->name = $d;
$this->color = '';
}
}
/******************************************************************************!
* \class DepartementList
******************************************************************************/
class DepartementList
{
var $randomColor;
var $deparList;
/**************************************************************************!
* \fn construct
**************************************************************************/
function __construct() {
$this->randomColor = new RandomColor(0.45);
}
/**************************************************************************!
* \fn add
**************************************************************************/
public function add($d) {
$this->deparList[] = new Departement($d);
}
/**************************************************************************!
* \fn getColor
**************************************************************************/
public function getColor($d) {
foreach ($this->deparList as $dep) {
if ($dep->name != $d) {
continue;
}
if (empty($dep->color)) {
$dep->color = $this->addColor($d);
}
return $this->colorName($d);
}
}
/**************************************************************************!
* \fn addColor
**************************************************************************/
private function addColor($d) {
//fwrite(STDERR, 'addColor: '.$d."\n");
$c = $this->colorName($d);
list($r, $g, $b) = $this->randomColor->nextRgb(0.24, 0.99);
print '\definecolor{'.$c.GENRE_M.'}{rgb}{'.$r.','.$g.','.$b."}\n";
list($r, $g, $b) = $this->randomColor->rgb(0.12, 0.99);
print '\definecolor{'.$c.GENRE_F.'}{rgb}{'.$r.','.$g.','.$b."}\n";
return $c;
}
/**************************************************************************!
* \fn colorName
**************************************************************************/
private function colorName($d) {
$d = str_replace('-', '', $d);
$d = str_replace("'", '', $d);
$d = str_replace('è', 'e', $d);
$d = str_replace('ô', 'o', $d);
return $d;
}
}
/******************************************************************************!
* \class Individu
******************************************************************************/
class Individu
{
var $nom;
var $prenom;
var $dateNaissance;
var $villeNaissance;
var $depNaissance;
var $dateMort;
var $villeMort;
var $titre;
var $label;
/**************************************************************************!
* \fn construct
**************************************************************************/
function __construct($i, $lieu, $departement) {
$this->nom = strtoupper($i[1]);
$this->prenom = $i[2];
$this->dateNaissance = $i[8];
$this->dateMort = $i[14];
if (array_key_exists($i[9], $lieu)) {
$this->villeNaissance = $lieu[$i[9]];
$this->depNaissance = $departement[$i[9]];
}
if (array_key_exists($i[15], $lieu)) {
$this->villeMort = $lieu[$i[15]];
}
$this->titre = $i[6];
$this->label = str_replace('[', '', $i[0]);
$this->label = str_replace(']', '', $this->label);
}
/**************************************************************************!
* \fn getColor
**************************************************************************/
public function getColor($genre, $departementList) {
if (! empty($this->depNaissance)) {
return '='.$departementList->getColor($this->depNaissance).$genre;
} else {
return '';
}
}
/**************************************************************************!
* \fn print
**************************************************************************/
public function print($niveau) {
print '{\begin{tabular}{@{}l@{}}';
print "$this->nom $this->prenom";
print "\\\\".
"$this->dateNaissance~$this->villeNaissance\\\\".
"$this->dateMort~$this->villeMort";
if ($niveau < 7) {
$age = $this->age();
print "\\\\$age$this->titre";
}
if (file_exists("build/$this->label.png")) {
print '\\\\\\includegraphics{build/'.$this->label.'.png}';
} else if (file_exists("build/$this->label.jpg")) {
print '\\\\\\includegraphics{build/'.$this->label.'.jpg}';
}
print '\end{tabular}'."}\n";
}
/**************************************************************************!
* \fn age
**************************************************************************/
public function age() {
if (empty($this->dateMort) ||
empty($this->dateNaissance)) {
return '';
}
$a1 = substr($this->dateNaissance, 0, 4);
$a2 = substr($this->dateMort, 0, 4);
if (! is_numeric($a1) ||
! is_numeric($a2)) {
return '';
}
$f1 = substr($this->dateNaissance, 0, 10);
$f2 = substr($this->dateMort, 0, 10);
if (strlen($f1) <= 4 || substr($f1, 4, 1) != '-' ||
strlen($f2) <= 4 || substr($f1, 4, 1) != '-') {
$a = intval($a2) - intval($a1);
return "$a ans ";
} else {
$n = new DateTime($f1);
$m = new DateTime($f2);
$a = $n->diff($m);
return $a->format('%y').' ans ';
}
}
}
/******************************************************************************!
* \class Arbre
******************************************************************************/
class Arbre
{
var $lieu;
var $departement;
var $departementList;
var $individus;
var $mariage;
var $famille;
var $niveau;
var $anneeMariage;
var $villeMariage;
var $pass;
var $pass2;
var $parent;
var $sens;
var $offsetNode;
var $offsetDate;
var $lmax;
var $below;
var $left;
var $right;
/**************************************************************************!
* \fn construct
**************************************************************************/
function __construct($lmax, $below, $left, $right) {
$this->niveau = 0;
$this->anneeMariage = 0;
$this->villeMariage = '';
$this->pass = 0;
$this->pass2 = 0;
$this->lmax = $lmax;
$this->below = $below;
$this->left = $left;
$this->right = $right;
}
/**************************************************************************!
* \fn init
**************************************************************************/
public function init($parent) {
$this->parent = $parent;
if ($this->parent == 1) {
$this->sens = -1;
} else {
$this->sens = 1;
}
$this->offsetNode = -26.6 * $this->sens;
$this->offsetDate = -26.6 * $this->sens;
}
/**************************************************************************!
* \fn readCSV
**************************************************************************/
public function readCSV($filename) {
$this->departementList = new DepartementList;
$table = 0;
if (($f = fopen($filename, "r")) !== false) {
while (($d = fgetcsv($f, 1000, ",")) !== false) {
if (empty($d[0])) {
continue;
}
switch (trim($d[0])) {
case 'Lieu':
$table = LIEU;
break;
case 'Individu':
$table = INDIVIDU;
break;
case 'Mariage':
$table = MARIAGE;
break;
case 'Famille':
$table = FAMILLE;
break;
default:
switch ($table) {
case LIEU:
if ($d[3] == 'Département') {
$this->departementList->add($d[2]);
$tmpDepartement[$d[0]] = $d[2];
} else {
$this->lieu[$d[0]] = $d[2];
$this->departement[$d[0]] = $tmpDepartement[$d[7]];
}
break;
case INDIVIDU:
$this->individus[$d[0]] =
new Individu($d, $this->lieu, $this->departement);
break;
case MARIAGE:
$this->mariage[$d[0]] = $d;
break;
case FAMILLE:
$this->famille[$d[1]] = $d[0];
break;
}
}
}
fclose($f);
}
}
/**************************************************************************!
* \fn getFirstNodeParent
**************************************************************************/
public function getFirstNodeParent($parent) {
return $this->mariage[array_key_first($this->mariage)][$parent];
}
/**************************************************************************!
* \fn printNode
**************************************************************************/
public function printNode($n, $genre) {
if (empty($n)) {
return;
}
$i = $this->individus[$n];
for ($j = 0; $j < $this->niveau; ++$j) {
print ' ';
}
if ($this->niveau == 0) {
print "\\";
} else {
print "child{ ";
}
$couleur = $i->getColor($genre, $this->departementList);
print "node [individu$couleur] ";
print "($i->label) ";
if ($this->niveau == 4) {
$offsetX = 3.5 * $this->sens;
print "at ($offsetX,$this->offsetNode) ";
if ($this->pass == 1) {
$this->offsetNode += 7.2 * $this->sens;
if ($this->pass2 == 1) {
$this->offsetNode += 0.9 * $this->sens;
}
$this->pass2 = 1 - $this->pass2;
}
$this->pass = 1 - $this->pass;
}
$i->print($this->niveau);
if ($this->niveau == 0 && $this->anneeMariage == 0) {
$this->anneeMariage = $this->mariage[$this->famille[$n]][3];
$index = $this->mariage[$this->famille[$n]][4];
if (array_key_exists($index, $this->lieu)) {
$this->villeMariage = $this->lieu[$index];
} else {
$this->villeMariage = '';
}
}
++$this->niveau;
if ($this->niveau < $this->lmax) {
$this->printParents($n);
}
--$this->niveau;
for ($j = 0; $j < $this->niveau; ++$j) {
print ' ';
}
if ($this->niveau > 0 && $this->niveau < $this->lmax - 1) {
if (! empty($this->famille[$n])) {
if ($this->niveau > 5) {
$s = $this->mariage[$this->famille[$n]][3];
if (substr($s, 0, 6) == 'avant ') {
$s = 'av. '.substr($s, 6, 4);
} else {
$s = substr($s, 0, 4);
}
} else {
$s = $this->mariage[$this->famille[$n]][3].' ';
$index = $this->mariage[$this->famille[$n]][4];
if (array_key_exists($index, $this->lieu)) {
$s .= $this->lieu[$index];
}
}
print 'edge from parent node[';
// left
if ($this->sens < 0) {
print 'left';
} else {
print 'right';
}
if ($this->niveau == 4) {
$this->left += 50;
} else if ($this->niveau == 2) {
$this->left += 5;
} else if ($this->niveau == 1) {
$this->left += 5;
}
print '='.$this->left.'mm';
// above
if ($this->niveau == 4) {
$this->left -= 50;
print ',above='.$this->offsetDate.'cm';
if ($this->pass == 0) {
$this->offsetDate += 7.2 * $this->sens;
if ($this->pass2 == 0) {
$this->offsetDate += 0.9 * $this->sens;
}
}
} else if ($this->niveau == 2) {
$this->left -= 5;
} else if ($this->niveau == 1) {
$this->left -= 5;
}
print ']{'."$s}";
}
}
if ($this->niveau == 1 && $this->anneeMariage != 0) {
print 'edge from parent node[';
print 'above='.$this->below.'mm,';
print 'left='.(-30 * $this->sens).'mm';
print ']{'."$this->anneeMariage $this->villeMariage}";
$this->anneeMariage = 0;
}
if ($this->niveau == 0) {
print ";\n";
} else {
print "}\n";
}
}
/**************************************************************************!
* \fn printParents
**************************************************************************/
private function printParents($n) {
if (array_key_exists($n, $this->famille)) {
if ($this->parent == 1) {
$this->printNode($this->mariage[$this->famille[$n]][1],
GENRE_M);
$this->printNode($this->mariage[$this->famille[$n]][2],
GENRE_F);
} else {
$this->printNode($this->mariage[$this->famille[$n]][2],
GENRE_F);
$this->printNode($this->mariage[$this->famille[$n]][1],
GENRE_M);
}
}
}
/**************************************************************************!
* \fn browseNode
**************************************************************************/
public function browseNode($n, $genre) {
if (empty($n)) {
return;
}
$i = $this->individus[$n];
$couleur = $i->getColor($genre, $this->departementList);
++$this->niveau;
if ($this->niveau < $this->lmax) {
$this->browseParents($n);
}
--$this->niveau;
}
/**************************************************************************!
* \fn browseParents
**************************************************************************/
private function browseParents($n) {
if (array_key_exists($n, $this->famille)) {
if ($this->parent == 1) {
$this->browseNode($this->mariage[$this->famille[$n]][1],
GENRE_M);
$this->browseNode($this->mariage[$this->famille[$n]][2],
GENRE_F);
} else {
$this->browseNode($this->mariage[$this->famille[$n]][2],
GENRE_F);
$this->browseNode($this->mariage[$this->famille[$n]][1],
GENRE_M);
}
}
}
}
/******************************************************************************!
* \fn main
******************************************************************************/
if ($argv[1] == 'tests') {
function testAge($n,$m,$a)
{
$i = new Individu(array('','','','','','','','',
$n,'','','','','', $m, ''));
$age = $i->age();
if ($age != $a) {
print "error: age $age($n, $m, $a)\n";
exit(1);
}
}
testAge('2000-02-02', '2001-02-02', 1);
testAge('2000-02-02', '2001-02-01', 0);
testAge('2000-02-02', '2001-01-02', 0);
testAge('2000-02-02', '2001', 1);
testAge('2000', '2001-12-31', 1);
print "OK\n";
} else {
$a = new Arbre($lmax, $below, $left, $right);
$a->readCSV($filename);
$a->init(1);
$a->browseNode($a->getFirstNodeParent(1), GENRE_M);
$a->init(2);
$a->browseNode($a->getFirstNodeParent(2), GENRE_F);
$a->init($parent);
fwrite(STDERR, 'Lieux: '.count($a->lieu)."\n");
fwrite(STDERR, 'Individus: '.count($a->individus)."\n");
fwrite(STDERR, 'Mariages: '.count($a->mariage)."\n");
fwrite(STDERR, 'Familles: '.count($a->famille)."\n");
if ($parent == 1) {
$genre = GENRE_M;
} else {
$genre = GENRE_F;
}
$a->printNode($a->getFirstNodeParent($parent), $genre);
}
?>