home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-04-29 | 103.0 KB | 4,622 lines |
- head 1.9;
- access;
- symbols
- stage1:1.6;
- locks; strict;
- comment @ * @;
-
-
- 1.9
- date 94.04.29.23.46.46; author peteric; state Exp;
- branches;
- next 1.8;
-
- 1.8
- date 94.04.27.11.37.54; author peteric; state Exp;
- branches;
- next 1.7;
-
- 1.7
- date 94.03.26.11.28.03; author peteric; state Exp;
- branches;
- next 1.6;
-
- 1.6
- date 94.03.10.21.28.26; author peteric; state Exp;
- branches;
- next 1.5;
-
- 1.5
- date 94.03.07.13.00.31; author peteric; state Exp;
- branches;
- next 1.4;
-
- 1.4
- date 94.03.07.12.44.14; author peteric; state Exp;
- branches;
- next 1.3;
-
- 1.3
- date 94.03.01.23.23.01; author peteric; state Exp;
- branches;
- next 1.2;
-
- 1.2
- date 94.02.27.19.32.55; author peteric; state Exp;
- branches;
- next 1.1;
-
- 1.1
- date 94.02.17.23.50.21; author peteric; state Exp;
- branches;
- next ;
-
-
- desc
- @Layout tools for ftree family tree formatter.
- @
-
-
- 1.9
- log
- @Fixed problem with the first marriage not being correctly
- linked in, so an intitial multiple marriage wouldn't get
- displayed correctly. Fixed bug in do_simple_layout and removed
- a now-redundant debug message (At least I hope it's redundant!)
- @
- text
- @/*************************************************************************
- *
- * $RCSfile: layout.c,v $
- *
- * $Author: peteric $
- *
- * $Date: 1994/04/27 11:37:54 $
- *
- * $State: Exp $
- *
- * $Revision: 1.8 $
- *
- * Purpose: Layout routines for ftree.
- *
- * $Log: layout.c,v $
- * Revision 1.8 1994/04/27 11:37:54 peteric
- * Fixed up the code to deal correctly with multiple marriages.
- * Added a number of debugging statements and removed some of
- * the redundant code - set_left_links etc. replacing them with
- * the mirror_right_links code. As a result, findleft_back()
- * and findleft_forw() can go too.
- * Major changes result from the fact that some pointers can now
- * point at marriage_t's or person_t's.
- * Finally, added a routine check_links to check that the pointer
- * referenced are valid and, where possible to check, correct. This
- * is conditional on CHECK_LINKS being defined, and is not currently
- * called.
- *
- * Revision 1.7 1994/03/26 11:28:03 peteric
- * Included multiple-marriage support.
- *
- * Revision 1.6 1994/03/10 21:28:26 peteric
- * Multiple pages working!
- *
- * Revision 1.5 1994/03/07 13:00:31 peteric
- * Reduced stringwidth const.
- *
- * Revision 1.4 1994/03/07 12:44:14 peteric
- * Passed on as first Version.
- *
- * Revision 1.3 1994/03/01 23:23:01 peteric
- * changes to complete layered adjustment of position
- * including auto-centering of parents.
- *
- * Revision 1.2 1994/02/27 19:32:55 peteric
- * fixed layout problems of previous versions.
- *
- * Revision 1.1 1994/02/17 23:50:21 peteric
- * Initial revision
- *
- *
- *************************************************************************/
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include <string.h>
- #include <assert.h>
-
- #include "ftree.h"
-
- /*
- * maximum number of times adjust_layout will attempt to get the
- * layout right. After this, it just gives up...
- */
- #define MAX_ADJUSTS 100
-
- static pmheader_t *findright_back(marriage_t *marriage, int level);
- static pmheader_t *findright_forw(marriage_t *marriage, int level);
- static void set_right_links(options_t *, marriage_t *, int);
- static void do_layout_part2(options_t *opts, marriage_t *, int level);
- static void find_boundingbox(options_t *opts, marriage_t *m);
- static void normalise_area(options_t *opts, marriage_t *m);
- static void check_parents(pmheader_t *person);
- pmheader_t * mof(pmheader_t *p, enum xpspec_t spec);
- static void mirror_right_links(options_t *opts);
- static int linkedto(pmheader_t *last, pmheader_t *this);
- static char *nameof(pmheader_t *this);
- void move_marriage(marriage_t *marriage, int dx);
- #ifdef SHOW_LAYOUT
- static void adjust_layout(FILE *outf, options_t *opts, marriage_t *startm);
- #else
- static void adjust_layout(options_t *opts);
- #endif
- #ifdef DEBUG
- static void show_generations(void);
- #ifdef CHECK_LINKS
- void check_links(void);
- #endif
- #endif
- extern char *strdup(const char*);
-
- /*(
- **********************************************************************************
- *
- * Function: print
- *
- *
- * Inputs:
- * opts
- *
- * Outputs:
- * (file)
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * Calls the routines to format and output PostScript statements which will draw
- * the family tree described in the opts array, using data from the mroot/proot
- * lists.
- *
- * The tree is assumed to be a true tree - i.e. one root node branching out to n
- * leaf nodes.
- *
- * If the named 'outputfile' is 'con' this is taken as a signal to write output to
- * the standard output stream instead of opening a new file.
- *
- **********************************************************************************
- )*/
-
- void print(options_t *opts)
- {
- FILE *outf;
- int i, sx, sy;
- marriage_t *startmarriage;
-
- if (strcmp(opts->outputfile, "-"))
- {
- outf = fopen(opts->outputfile, "w");
- if (outf == NULL)
- {
- fprintf(stderr, "ftree: cannot write file '%s'\n", opts->outputfile);
- exit(1);
- }
- }
- else
- outf = stdout;
-
- /*
- * set things up...
- */
- sx = (opts->pagewidth - opts->rmargin)/2;
- sy = opts->titlefont.linespc + 3*opts->personfont.linespc;
- startmarriage = findfirstmarriage(opts->startperson);
- for (i = 0; i < MAXLEVELS; i++)
- generation[i].first = generation[i].last = NULL;
-
- dbprintf(("\n----------------------------------- do_simple_layout -----------------------------------------------\n"));
-
- /*
- * lay out our tree
- */
- do_simple_layout(opts, startmarriage, sx, sy, 0);
-
- dbprintf(("\n----------------------------------- do_layout_part2 ------------------------------------------------\n"));
-
- /*
- * now the layout is set, set up the left & right pointers in
- * the person records so that the set_links routines have something
- * to work on.
- */
- do_layout_part2(opts, startmarriage, 0);
-
- dbprintf(("\n----------------------------------- set_left/right_links -------------------------------------------\n"));
-
- /*
- * set up the left & right links from the generation array
- * into the main structure.
- */
- generation[0].first = (pmheader_t*)startmarriage;
- nlevels = 1;
- set_right_links(opts, startmarriage, 1);
-
- /*
- * create the right links.
- */
- mirror_right_links(opts);
-
- #ifdef DEBUG
- dbprintf(("\n----------------------------------- show_generations -----------------------------------------------\n"));
-
- show_generations();
- #endif
-
- dbprintf(("\n----------------------------------- adjust_layout --------------------------------------------------\n"));
-
- /*
- * use the links to adjust the gap btw. people on a line.
- */
- #ifdef SHOW_LAYOUT
- do_prolog(outf, opts);
- do_title(outf, opts, startmarriage);
- print_tree(outf, opts, startmarriage);
- adjust_layout(outf, opts, startmarriage);
- print_tree(outf, opts, startmarriage);
- #else
- adjust_layout(opts);
-
- dbprintf(("\n----------------------------------- normalise_area -------------------------------------------------\n"));
-
- /*
- * get the bounding box for the chart & use it to left-adjust the
- * chart (so that the left of the chart is on page 1) and set up
- * the PostScript BoundingBox comment.
- */
- normalise_area(opts, startmarriage);
-
- dbprintf(("\n----------------------------------- do_prolog ------------------------------------------------------\n"));
-
- /*
- * print out the PostScript DSC prolog stuff
- */
- do_prolog(outf, opts);
-
- dbprintf(("\n----------------------------------- do_title -------------------------------------------------------\n"));
-
- /*
- * put a title on the page
- */
- do_title(outf, opts, startmarriage);
-
- dbprintf(("\n----------------------------------- print_tree -----------------------------------------------------\n"));
-
- /*
- * print our tree
- */
- print_tree(outf, opts, startmarriage);
- #endif
-
- dbprintf(("\n----------------------------------- do_epilog ------------------------------------------------------\n"));
-
- /*
- * finish it off
- */
- do_epilog(outf, opts);
-
- /*
- * close the file.
- */
- if (outf != stdout)
- fclose(outf);
- else
- fflush(outf);
- }
-
- /*(
- **********************************************************************************
- *
- * Function: do_simple_layout
- *
- *
- * Inputs:
- * opts - current option settings
- * id - id of person
- * x, y - initial placement of marriage
- *
- * Outputs:
- * none.
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * Determines the initial placement of the marriage(s) connected to 'id' and those
- * marriages made by their children. This initial placement ignores issues of
- * overlap; this is dealt with later. The main element here is the general x
- * placement, calculation of y placement, and the setting up of various values in
- * the person_t and marriage_t structures.
- *
- **********************************************************************************
- )*/
-
- void do_simple_layout(options_t *opts, marriage_t *marriage, int x, int y, int level)
- {
- int children;
- int ptwidth, startx, childy;
- person_t *child;
- marriage_t *m;
-
- dbprintf(( "\ndo_simple_layout: do layout level %d\n", level));
-
- while(marriage)
- {
- dbprintf(( "do_simple_layout: set marriage %s at %d x %d.\n", nameof((pmheader_t*)marriage), x, y));
- marriage->h.xpos = x;
- marriage->h.ypos = y;
- if (marriage->next)
- marriage->h.right = (pmheader_t *)marriage->next;
- assert(marriage->h.width != 0);
-
- /*
- * calculate various child<->parent figures - e.g the width of
- * the children's line, and make various relationship links.
- */
- children = 0;
- ptwidth = 0;
- child = marriage->firstchild;
- while(child != NULL)
- {
- children++;
- dbprintf(( "do_simple_layout: setting up child %d (%s)\n", children, child->firstname));
- m = findfirstmarriage(child->id);
- child->firstmarriage = m;
- child->lastmarriage = m;
-
- assert((m != NULL && child->married) || (m == NULL && !child->married));
-
- while(m)
- {
- /*
- * this should perhaps be outside the loop?
- */
- m->backlink = marriage;
- dbprintf(("do_simple_layout: setting backlink for child marriage %s to marriage %s\n",
- nameof((pmheader_t*)child->firstmarriage), nameof((pmheader_t*)marriage) ));
-
- ptwidth += m->h.width;
- m->h.right = (pmheader_t *)m->next;
-
- /*
- * want to remember the last marriage - this will
- * get overwritten until m->next is NULL.
- */
- child->lastmarriage = m;
- m = m->next;
- }
- /*
- * this bit of trickery is so that we recalculate the child's width
- * if we change fullname because the parent's names are different.
- * We already coped with it if married was set.
- */
- child->fullname = !streq(child->family, marriage->husband->family);
- if (child->fullname)
- child->h.width = widthof(opts, child);
- child->fullname |= child->married;
- child->h.level = level + 1;
-
- dbprintf(( "do_simple_layout: child setup ... 2\n"));
- /*
- * set up the level pointers (right side only required).
- */
- if (child->married)
- {
- if (child->nextchild)
- child->lastmarriage->h.right = mof((pmheader_t*)child->nextchild, XP_FIRST);
- else
- child->lastmarriage->h.right = NULL;
-
- if (child->lastchild)
- {
- if (child->lastchild->married)
- child->lastchild->lastmarriage->h.right = (pmheader_t *)child->firstmarriage;
- else
- child->lastchild->h.right = (pmheader_t *)child->firstmarriage;
- child->lastchild->h.right = (pmheader_t*)child->firstmarriage;
- }
- child->h.right = NULL;
- }
- else
- {
- ptwidth += child->h.width;
- if (child->nextchild)
- child->h.right = mof((pmheader_t*)child->nextchild, XP_FIRST);
- else
- child->h.right = NULL;
- }
- dbprintf(( "do_simple_layout: child setup ... 3\n"));
-
- child = child->nextchild;
- }
- dbprintf(( "do_simple_layout: finished child setup\n"));
- marriage->children = children;
- marriage->h.level = level;
-
- /*
- * ptwidth is only the width of the connecting line ... it doesn't
- * include the space at each end.
- */
- if (marriage->children >= 1)
- {
- ptwidth -= (pwidthof((pmheader_t*)marriage->firstchild, XP_FIRST) +
- pwidthof((pmheader_t*)marriage->lastchild, XP_FIRST)) / 2;
- }
- dbprintf(( "do_simple_layout: ptwidth: %d children %d\n", ptwidth, marriage->children));
-
- if (marriage->children > 0)
- {
- childy = y + opts->vspace;
- switch (marriage->hint)
- {
- case H_RIGHT:
- startx = x - (ptwidth * 0.25);
- break;
- case H_LEFT:
- startx = x - (ptwidth * 0.75);
- break;
- default:
- case H_CENTERED:
- startx = x - (ptwidth * 0.5);
- break;
- }
- dbprintf(( "do_simple_layout: startx: %d (= %d - (%d/2)), childy: (%d + %d), children: %d\n",
- startx, x, ptwidth, y, opts->vspace, marriage->children));
-
- /*
- * have a go at placing the children & their marriages
- */
- child = marriage->firstchild;
- while(child != NULL)
- {
- child->h.xpos = startx;
- child->h.ypos = childy;
- dbprintf(( "do_simple_layout: child %s @@ %dx%d\n", nameof((pmheader_t*)child), startx, childy));
- if (child->married)
- {
- m = child->firstmarriage;
- while(m)
- {
- m->h.xpos = startx;
- m->h.ypos = childy;
- if (m->next)
- startx += (m->h.width + m->next->h.width) / 2;
- else if (child->nextchild)
- startx += (m->h.width +
- pwidthof((pmheader_t*)child->nextchild, XP_FIRST)) / 2;
-
- dbprintf(( "do_simple_layout: marriage %s at %dx%d, next: %d\n",
- nameof((pmheader_t*)m), m->h.xpos, m->h.ypos, startx));
- m = m->next;
- }
- }
- else if (child->nextchild)
- startx += (child->h.width +
- pwidthof((pmheader_t*)child->nextchild, XP_FIRST)) / 2;
- child = child->nextchild;
- }
-
- dbprintf(( "do_simple_layout: searching for marriages \n"));
-
- child = marriage->firstchild;
- while(child != NULL)
- {
- if (child->married)
- {
- /*
- * these positions should be the child's ones.
- */
- do_simple_layout(opts, child->firstmarriage,
- child->h.xpos, child->h.ypos, level+1);
- }
- child = child->nextchild;
- }
- }
- dbprintf(( "do_simple_layout: finished marriage.\n"));
-
- if (marriage->next)
- x += (marriage->h.width + marriage->next->h.width) / 2;
-
- marriage = marriage->next;
- }
-
- dbprintf(( "do_simple_layout: finished simple layout\n"));
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: do_layout_part2
- *
- *
- * Inputs:
- * opts - options array
- * id - starting ID code.
- * level - generation/recursion level.
- *
- * Outputs:
- * none.
- *
- * Description:
- *
- * Modifies the data structure by adding in the left and right pointers for inter-
- * marriage links. Assumes that do_simple_layout has already been done, swhich
- * sets up the in-marriage links between children and linked marriages.
- *
- ***********************************************************************************
- )*/
-
- static void do_layout_part2(options_t *opts, marriage_t *marriage, int level)
- {
- pmheader_t *this;
- person_t *child;
-
- dbprintf(( "\ndo_layout_part2: marriage level %d\n", level));
-
- if (marriage->children > 0)
- {
- child = marriage->firstchild;
- while(child != NULL)
- {
- if (child->married)
- {
- do_layout_part2(opts, child->firstmarriage, level + 1);
- }
- child = child->nextchild;
- }
- }
-
- /*
- * fill in the NULL links that aren't done above. Must wait 'till all
- * the backlinks etc. are done.
- */
- this = findright_back(marriage, level + 1);
-
- dbprintf(("do_layout_part2: findright lev %d returns %s, firstchild: %s\n",
- level+1, nameof(this), nameof((pmheader_t*) marriage->firstchild) ));
-
- child = marriage->lastchild;
-
- if (child && child->married)
- child->lastmarriage->h.right = this;
- else if (child)
- child->h.right = this;
- else
- dbprintf(("do_layout_part2: no firstchild to set up!\n"));
- }
-
- /*(
- **********************************************************************************
- *
- * Function: mirror_right_links
- *
- *
- * Inputs:
- * opts - global options arary
- *
- * Outputs:
- * none.
- *
- * Description:
- *
- * Create the doubly linked list from the singly linked left/right generation
- * list for each generation.
- *
- **********************************************************************************
- )*/
-
- static void mirror_right_links(options_t *opts)
- {
- pmheader_t *next, *curr;
- int i;
-
- dbprintf(("\nmirror_right_links: start"));
-
- /*
- * generate the backlink 'right' for the left link 'left' for each
- * node in the lists pointed to by the generation array.
- */
- for(i = 0; i < nlevels; i++)
- {
- curr = generation[i].first;
-
- dbprintf(("\nmirror_right_links: level %d: %s ",i,nameof(curr)));
-
- if (curr) /* sanity check */
- {
- while(curr->right)
- {
- next = curr->right;
- next->left = curr;
- curr = next;
- }
- generation[i].last = curr;
- }
- }
-
- dbprintf(("\nmirror_right_links: end\n"));
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: find_boundingbox
- *
- *
- * Inputs:
- * opts - global options structure
- * id - id code identifying the initial point
- * level - generation/recursion level
- *
- * Outputs:
- * none.
- *
- * Description:
- *
- * Searches the tree looking for the extremities of the useful area. The area used
- * by the tree is notionally 0,0 -> x,y, where x,y is the size required to print
- * it, but the algorithm can end up with an area -a,-b -> x,y. This routine
- * returns these values by comparing the current limit with the calculated size of
- * all nodes found.
- *
- * This is done in part with some macros which make life a little easier.
- *
- ***********************************************************************************
- )*/
-
- #define set_low(var, val) {if ((var) > (val)) (var) = (val); }
- #define set_high(var, val) {if ((var) < (val)) (var) = (val); }
-
- static void find_boundingbox(options_t *opts, marriage_t *marriage)
- {
- person_t *p;
- while (marriage)
- {
- dbprintf(("find_boundingbox: marriage %s & %s: ", nameof((pmheader_t*)marriage)));
-
- set_low(opts->bbly, marriage->h.ypos);
- set_high(opts->bbuy, marriage->h.ypos);
- set_low(opts->bblx, marriage->h.xpos - marriage->h.width / 2);
- set_high(opts->bbux, marriage->h.xpos + marriage->h.width / 2);
-
- if (marriage->children > 0)
- {
- dbprintf(("child %s\n", marriage->firstchild->firstname));
- p = marriage->firstchild;
- while(p)
- {
- if (p->married)
- {
- find_boundingbox(opts, p->firstmarriage);
- }
- else
- {
- set_low(opts->bbly, p->h.ypos);
- set_high(opts->bbuy, p->h.ypos);
- set_low(opts->bblx, p->h.xpos - p->h.width / 2);
- set_high(opts->bbux, p->h.xpos + p->h.width / 2);
- }
- p = p->nextchild;
- }
- }
- else
- dbprintf(("no children\n"));
-
- marriage = marriage->next;
- }
- }
- #undef set_low
- #undef set_high
-
- /*(
- ***********************************************************************************
- *
- * Function: set_right_links
- *
- *
- * Inputs:
- * opts - global options structure
- * id - id code identifying the initial point
- * level - generation/recursion level
- *
- * Outputs:
- * none.
- *
- * Description:
- *
- * Sets up generation[] array by scanning through the tree looking for leftmost
- * people on a level which hasn't been defined yet. When found, the left pointer
- * in the array is set to this person.
- *
- ***********************************************************************************
- )*/
-
- static void set_right_links(options_t *opts, marriage_t *marriage, int level)
- {
- person_t *p;
-
- if (marriage == NULL)
- return;
-
- while (marriage)
- {
- dbprintf(("set_right_links: marriage %s level %d: ",nameof((pmheader_t*)marriage), level));
-
- /*
- * operate the generation array on a first-come-first-served
- * basis, so we get the end points. We actually scan the whole
- * tree, though.
- */
- if (generation[level].first == NULL)
- {
- generation[level].first = mof((pmheader_t*)marriage->firstchild, XP_FIRST);
- dbprintf(("FIRST: "));
- }
- if (nlevels <= level)
- nlevels = level+1;
-
- if (marriage->children > 0)
- {
- dbprintf(("child %s (lev: %d)\n",
- nameof((pmheader_t*)marriage->firstchild),marriage->firstchild->h.level));
-
- p = marriage->firstchild;
- while(p)
- {
- if (p->married)
- {
- set_right_links(opts, p->firstmarriage, level+1);
- }
- p = p->nextchild;
- }
- }
- else
- dbprintf(("no children\n"));
-
- marriage = marriage->next;
- }
- }
-
- /*(
- **********************************************************************************
- *
- * Function: adjust_layout
- *
- *
- * Inputs:
- * opts - current option set
- * outf - output file [debug mode only]
- * startm - start marriage point [debug mode only]
- *
- * Outputs:
- * (file)
- *
- * Error Handling:
- * None.
- *
- * Description:
- *
- * This routine takes the initial positions assigned by the routine
- * do_simple_layout and adjusts the positions such that people do not overlap.
- *
- * The following checks are performed:
- * 1. That people do not overlap. This is done for all pairs of people.
- * 2. That for any triple a,b,c of siblings where b is not married b is not
- * closer to a than c.
- * 3. That for any oldest or youngest child the distance to the next sibling
- * is not greater than necessary. i.e. given siblings a b c d, that the
- * distance b - a is not greater than the half the sum of the widths of a and
- * b, and similarly for c and d. This is only done if a anc d are single.
- * 4. When any person is moved, the parents' location is checkedto ensure that
- * they remain centered.
- *
- **********************************************************************************
- )*/
-
- #ifdef SHOW_LAYOUT
- static void adjust_layout(FILE *outf, options_t *opts, marriage_t *startm)
- #else
- static void adjust_layout(options_t *opts)
- #endif
- {
- int adjust_count, gen, dx, moved;
- int move_parents = FALSE;
- pmheader_t *this, *last;
- #define c_person ((person_t *)this)
- #define c_marriage ((marriage_t *)this)
- #define l_person ((person_t *)last)
- #define l_marriage ((marriage_t *)last)
- person_t *p2;
-
- dbprintf(("adjust_layout: start\n"));
- adjust_count = 0;
- do
- {
- moved = FALSE;
- for(gen = 0; gen < nlevels; gen++)
- {
- this = generation[gen].first;
- last = NULL;
- dbprintf(("adjust_layout: generation %d (starts with %s)\n", gen, nameof(this)));
-
- while(this)
- {
- if (last != NULL)
- {
- int this_w, last_w, this_x, last_x;
-
- /*
- * check to see if they overlap. Overlapping
- * includes the area required to print the name
- * etc, hence the 'width' calculation.
- */
- this_x = xposof(this, XP_FIRST);
- last_x = xposof(last, XP_LAST);
- this_w = pwidthof(this, XP_FIRST);
- last_w = pwidthof(last, XP_LAST);
-
- dx = (this_x - last_x);
- dx -= ((this_w + last_w) / 2 );
-
- dbprintf(("examining pair %s & %s (%d w: %d vs %d w: %d), dx = %d\n",
- nameof(last), nameof(this), last_x, last_w, this_x, this_w, dx));
-
- if (dx < -1)
- {
- dx = - dx;
-
- /*
- * move the people on this line by the ammount
- * these two overlap, plus the width of each side of
- * the area they occupy.
- */
- moved = TRUE;
- dbprintf(("adjust_layout: set moved true.\n"));
-
- switch (this->type)
- {
- case HT_PERSON:
- p2 = (person_t*)this;
- while(p2)
- {
- move_tree(p2, dx);
- p2 = p2->nextchild;
-
- }
- move_parents = TRUE;
- break;
-
- case HT_MARRIAGE:
- move_marriage(c_marriage, dx);
- move_parents = TRUE;
- break;
- }
- }
- else if (dx > 1 && linkedto(last, this))
- {
- /*
- * See if two siblings are unreasonably far apart
- * as a result of others moving.
- */
- if (last->type == HT_PERSON && l_person->lastchild == NULL && !l_person->married)
- {
- dbprintf(("adjust_layout: moving elder child %s closer to %s by %d\n",
- nameof(last), nameof(this), dx));
- last->xpos += dx;
- dbprintf(("adjust_layout: set moved true.\n"));
- moved = TRUE;
- move_parents = TRUE;
- }
- if (this->type == HT_PERSON && c_person->nextchild == NULL && !c_person->married)
- {
- dbprintf(("adjust_layout: moving youngest child %s closer to %s by %d\n",
- nameof(this), nameof(last), dx));
- this->xpos -= dx;
- dbprintf(("adjust_layout: set moved true.\n"));
- moved = TRUE;
- move_parents = TRUE;
- }
- }
-
- if (linkedto(last, this))
- {
- /*
- * check that people don't get left squeezed up
- * when there's plenty of space elsewhere.
- */
- if (this->type == HT_PERSON && c_person->nextchild != NULL && !c_person->married)
- {
- person_t *nc;
- int dx2, diff;
-
- nc = c_person->nextchild;
- dx2 = xposof((pmheader_t*)nc, XP_FIRST) - this->xpos;
- dx2 -= ((c_person->h.width + pwidthof((pmheader_t*)nc, XP_FIRST)) / 2 );
- diff = dx2 - dx;
- dbprintf(("adjust_layout: check centering: %s <- %d -> %s <- %d -> %s (out by: %d)\n",
- nameof(last), dx, nameof(this), dx2, nameof((pmheader_t*)nc), diff / 2));
- if (diff > 1)
- {
- dbprintf(("adjust_layout: right centering child %s by %d\n",
- nameof(this), diff / 2));
- this->xpos += diff / 2;
- dbprintf(("adjust_layout: set moved true.\n"));
- moved = TRUE;
- }
- else if (diff < -1)
- {
- dbprintf(("adjust_layout: left centering child %s by %d\n",
- nameof(this), diff / 2));
- this->xpos += diff / 2;
- dbprintf(("adjust_layout: set moved true.\n"));
- moved = TRUE;
- }
- }
- }
- if (move_parents)
- {
- check_parents(this);
- move_parents = FALSE;
- }
- }
-
- last = this;
- this = this->right;
- }
- }
- if (moved)
- {
- dbprintf(("\nadjust_layout: rerun; people moved!\n\n"));
- }
- adjust_count++;
- #ifdef SHOW_LAYOUT
- print_tree(outf, opts, startm);
- fprintf(outf, "showpage\n");
- #endif
- } while(moved && adjust_count < MAX_ADJUSTS);
- if (adjust_count == MAX_ADJUSTS)
- {
- fprintf(stderr, "adjust_layout: too much adjusting! - loop in layout.\n");
- }
- dbprintf_note(("adjust_layout: took %d tries to adjust layout.\n", adjust_count));
- dbprintf(("adjust_layout: end\n"));
- #undef c_person
- #undef c_marriage
- #undef l_person
- #undef l_marriage
- }
-
- /*(
- **********************************************************************************
- *
- * Function: check_parents
- *
- *
- * Inputs:
- * person - the person (or one of them) who has moved.
- *
- * Outputs:
- * int - flag set true if last & this linked.
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * Check to see if the parents of the child referenced should be moved, as the
- * child has just been. Currently, this basically means ensure that the parents
- * are always centered above the children. Later the bias system used in
- * do_simple_layout might be more appropriate.
- *
- * This routine checks parents back to the tree's root using the backlink.
- *
- **********************************************************************************
- )*/
-
- static void check_parents(pmheader_t *this)
- {
- int dxp, xp, fc, lc;
- marriage_t *m = NULL;
-
- switch(this->type)
- {
- case HT_PERSON:
- m = ((person_t*)this)->parents;
- break;
-
- case HT_MARRIAGE:
- m = (marriage_t*)this;
- break;
- }
-
- while(m)
- {
- dbprintf(("check_parents: checking marriage %s\n", nameof((pmheader_t*)m) ));
-
- if (m->firstchild)
- {
- /*
- * get range of X used by children of this marriage...
- */
- fc = xposof((pmheader_t*)m->firstchild, XP_FIRST);
- lc = xposof((pmheader_t*)m->lastchild, XP_FIRST);
- dxp = fc - lc;
- if (dxp < 0)
- dxp = - dxp;
- xp = fc + (dxp / 2);
-
- /*
- * and check that the marriage is decently centred.
- */
- if (abs(xp - m->h.xpos) > 1)
- {
- dbprintf(("check_parents: children range %d to %d: move parents by %d to %d\n",
- fc, lc, xp - m->h.xpos, xp));
- m->h.xpos = xp;
- }
- }
- m = m->backlink;
- }
- }
-
- /*(
- **********************************************************************************
- *
- * Function: linkedto
- *
- *
- * Inputs:
- * last - a person to check who is left of 'this'
- * this - a person to check right of 'last'
- *
- * Outputs:
- * int - flag set true if last & this linked.
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * Check to see if the person referenced by 'last' and the person referenced by
- * 'this' are siblings, or, if they refer to marriages, are remarriages. Basically
- * return TRUE if these people are on the same line & are direct family.
- *
- **********************************************************************************
- )*/
-
- static int linkedto(pmheader_t *last, pmheader_t *this)
- {
- if (last->type == HT_PERSON)
- return ((person_t*)last)->nextchild == (person_t*)this;
- else
- return ((marriage_t *)last)->next == (marriage_t *)this;
- }
-
- /*(
- **********************************************************************************
- *
- * Function: move_tree
- *
- *
- * Inputs:
- * marriage - the base of the tree to move
- * dx - the ammount by which to move the tree
- *
- * Outputs:
- * none.
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * Moves the tree based at 'person' by an ammount 'dx' in the X direction. No
- * effect in the Y direction.
- *
- **********************************************************************************
- )*/
-
- void move_tree(person_t *person, int dx)
- {
- person_t *child;
- marriage_t *marriage;
-
- dbprintf(( "move_tree: move person %s %s by %d\n",
- person->firstname, person->family, dx));
-
- if (person->married)
- {
- marriage = person->firstmarriage;
- while(marriage)
- {
- marriage->h.xpos += dx;
-
- child = marriage->firstchild;
- while(child)
- {
- move_tree(child, dx);
- child = child->nextchild;
- }
- marriage = marriage->next;
- }
- }
- else
- person->h.xpos += dx;
- }
-
- void move_marriage(marriage_t *marriage, int dx)
- {
- person_t *child;
-
- dbprintf(( "move_marriage: move by %d\n", dx));
-
- while(marriage)
- {
- marriage->h.xpos += dx;
-
- child = marriage->firstchild;
- while(child)
- {
- move_tree(child, dx);
- child = child->nextchild;
- }
- marriage = marriage->next;
- }
-
- }
- /*(
- ***********************************************************************************
- *
- * Function: findright_back
- *
- *
- * Inputs:
- * marriage - pointer to the marriage from which to look
- * level - the desired level.
- *
- * Outputs:
- * person_t * - pointer to the person found, or NULL
- *
- * Error Handling:
- * in case of error, and particularly when marriage ptr. or
- * the backlink is null, NULL is returned.
- *
- * Description:
- *
- * Searches for the next person at the desired level left from the current
- * marriage. This search may proceed back as far as is necessary (or possible).
- * This routine uses findright_forw to search forwards (younger) from given start
- * points.
- *
- * The search uses the backlink which was constrcted when the initial layout was
- * done, as the mapping from child to parent is one-to-many so it cannot be
- * searched for.
- *
- * The primary use for this routine is in the construction of the left/right links
- * which link up members of the same generation in order.
- *
- ***********************************************************************************
- )*/
-
- static pmheader_t *findright_back(marriage_t *marriage, int level)
- {
- pmheader_t *q;
- person_t *p;
- marriage_t *m, *mback;
-
- if (marriage == NULL)
- {
- dbprintf(("findright_back: no marriage!!.\n"));
- return NULL;
- }
- mback = marriage->backlink;
- if (mback == NULL)
- {
- dbprintf(("findright_back: no backlink.\n"));
- return NULL;
- }
-
- while(marriage)
- {
- m = marriage->backlink;
-
- dbprintf(("findright_back: look for person from %s (level %d) at level %d (backlink %spresent)\n",
- nameof((pmheader_t*)marriage), marriage->h.level, level, m ? "" : "not "));
-
- if (m->lastchild != marriage->husband && m->lastchild != marriage->wife)
- {
- /*
- * marriage not first child - try some of the children.
- *
- * First find out which parent is the child of the marriage given.
- */
- p = m->firstchild;
- while(p != NULL && p != marriage->husband && p != marriage->wife)
- {
- p = p->nextchild;
- }
-
- /*
- * p is should now point to the child of the older marriage who is
- * a parent in this one. (p == NULL) is an error.
- */
- p = p->nextchild;
- assert(p != NULL);
- while (p)
- {
- dbprintf(("findright_back: examining child: %s\n", nameof((pmheader_t*)p)));
-
- /*
- * if the level's match, this is it!
- */
- if (p->h.level == level)
- {
- dbprintf(("findright_back: found %s %s at level %d\n",
- p->firstname, p->family, p->h.level));
- return mof((pmheader_t*)p, XP_FIRST);
- }
-
- /*
- * levels didn't match. Try following this marriage...
- * (p->h.level < level implies that we are too old still)
- */
- if (p->h.level < level && p->married)
- {
- q = findright_forw(p->firstmarriage, level);
- if (q)
- {
- return q;
- }
- }
- #ifdef DEBUG
- else if (p->married)
- dbprintf(("findright_back: child married, but level too high already to match.\n"));
- else
- dbprintf(("findright_back: child not married, cannot continue here.\n"));
- #endif
- p = p->nextchild;
- }
- }
-
- dbprintf(("findright_back: %snext marriage.\n", marriage->next ? "" : "no "));
-
- marriage = marriage->next;
- }
-
- dbprintf(("findright_back: calling findright_back lev %d to check previous links\n",level));
-
- q = findright_back(mback, level);
- return q;
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: findright_forw
- *
- *
- * Inputs:
- * marriage - pointer to the marriage from which to look
- * level - level which is being looked for.
- *
- * Outputs:
- * person_t * - pointer to person found, or NULL
- *
- * Error Handling:
- *
- *
- * Description:
- *
- * Finds the next person at the desired level. The match condition required that
- * the person found is the leftmost person possible from the given start position.
- *
- ***********************************************************************************
- )*/
-
- static pmheader_t *findright_forw(marriage_t *marriage, int level)
- {
- pmheader_t *r;
- person_t *p, *q;
- marriage_t *m;
-
- dbprintf(("findright_forw: look for person from %s / %s at level %d\n",
- marriage->husband->firstname, marriage->wife->firstname, level));
-
- /*
- * go back looking at each older child's tree to see if they have
- * a child at the appropriate level.
- */
- while(marriage)
- {
- p = marriage->firstchild;
- while(p)
- {
- if (p->h.level == level)
- {
- dbprintf(("findright_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->h.level));
- return mof((pmheader_t*)p, XP_FIRST);
- }
-
- if (p->married)
- {
- /*
- * look through the person's children (if any) & check.
- * If any are married, recurse to check them too.
- */
- m = p->firstmarriage;
- while(m)
- {
- q = m->firstchild;
- while(q)
- {
- /*
- * found it!
- */
- if (q->h.level == level)
- {
- dbprintf(("findright_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->h.level));
- return mof((pmheader_t*)q, XP_FIRST);
- }
-
- if (q->married)
- {
- r = findright_forw(q->firstmarriage, level);
- if (r)
- {
- return (pmheader_t*)r;
- }
- }
-
- q = q->nextchild;
- }
- m = m->next;
- }
- }
- else
- dbprintf(("findright_forw: %s not married & not correct level (%d) => not suitable.\n",
- p->firstname, level));
-
- p = p->nextchild;
- }
- dbprintf(("findright_forw: %snext marriage.\n", marriage->next ? "" : "no "));
-
- marriage = marriage->next;
- }
-
- dbprintf(("findright_forw: nothing found.\n"));
- return NULL;
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: xposof
- *
- *
- * Inputs:
- * p - person pointer.
- * spec - used to determine which marriage to use, if any.
- *
- * Outputs:
- * int - xpos value of a person/marriage
- *
- * Description:
- *
- * Returns the xpos value for person. If person not married this is just the xpos
- * of the person. For marriages, because a person may have more than one location,
- * 'spec' is used to determine which of the posssible marriages to return the
- * position of. Currently, only the first and last in the list are needed.
- *
- ***********************************************************************************
- )*/
-
- int xposof(pmheader_t *p, enum xpspec_t spec)
- {
- if (p)
- {
- switch(p->type)
- {
- case HT_PERSON:
- if (((person_t*)p)->married)
- {
- if (spec == XP_FIRST)
- return ((person_t*)p)->firstmarriage->h.xpos;
- else
- return ((person_t*)p)->lastmarriage->h.xpos;
- }
- else
- return p->xpos;
-
- case HT_MARRIAGE:
- return p->xpos;
- }
- }
- dbprintf(("WARNING: NULL pointer passed to xposof()\n"));
- return 0;
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: pwidthof
- *
- *
- * Inputs:
- * p - person pointer.
- * spec - used to determine which marriage to use, if any.
- *
- * Outputs:
- * int - width of a person/marriage
- *
- * Description:
- *
- * Returns the width for person or marriage. If person not married this is just
- * the width of the person. For marriages, because a person may have more than one
- * marriage and hence width, 'spec' is used to determine which of the posssible
- * marriages to return the width of. Currently, only the first and last in the
- * list are needed.
- *
- ***********************************************************************************
- )*/
-
- int pwidthof(pmheader_t *p, enum xpspec_t spec)
- {
- if (p)
- {
- switch(p->type)
- {
- case HT_PERSON:
- if (((person_t*)p)->married)
- {
- if (spec == XP_FIRST)
- return ((person_t*)p)->firstmarriage->h.width;
- else
- return ((person_t*)p)->lastmarriage->h.width;
- }
- else
- return p->width;
-
- case HT_MARRIAGE:
- return p->width;
- }
- }
- dbprintf(("WARNING: NULL pointer passed to pwidthof()\n"));
- return 0;
- }
-
-
- /*(
- ***********************************************************************************
- *
- * Function: mof
- *
- *
- * Inputs:
- * p - person pointer.
- * spec - used to determine which marriage to use, if any.
- *
- * Outputs:
- * int - xpos value of a person/marriage
- *
- * Description:
- *
- * Returns the marriage header for person. If person not married this is simply
- * the header passed in. Because a person may have more than one marriage, 'spec'
- * is used to determine which of the posssible marriages to return the position
- * of. Currently, only the first and last in the list are needed.
- *
- ***********************************************************************************
- )*/
-
- pmheader_t * mof(pmheader_t *p, enum xpspec_t spec)
- {
- if (p)
- {
- switch(p->type)
- {
- case HT_PERSON:
- if (((person_t*)p)->married)
- {
- if (spec == XP_FIRST)
- return (pmheader_t*)((person_t*)p)->firstmarriage;
- else
- return (pmheader_t*)((person_t*)p)->lastmarriage;
- }
- else
- return p;
-
- case HT_MARRIAGE:
- return p;
- }
- }
- dbprintf(("WARNING: NULL pointer passed to mof()\n"));
- return NULL;
- }
-
- /*(
- ***********************************************************************************
- *
- * Function: normalise_area
- *
- *
- * Inputs:
- * opts - global options
- * marriage - marriage root
- *
- * Outputs:
- * None.
- *
- * Description:
- *
- * Calls find_boundingbox to calculate the area used by the chart. It then forces
- * the chart's left egde to be visible on the first page printed by adding any
- * negative offset to the x coords of the chart's elements.
- *
- ***********************************************************************************
- )*/
-
- static void normalise_area(options_t *opts, marriage_t *marriage)
- {
- person_t *p;
-
- /*
- * find the bounding box for the diagram; this gets
- * used in the %%BoundingBox: DSC comment.
- */
- opts->bblx = 999;
- opts->bbly = 999;
- opts->bbux = -999;
- opts->bbuy = -999;
- find_boundingbox(opts, marriage);
-
- if (opts->bblx < 0)
- {
- int dx = - opts->bblx;
-
- while(marriage)
- {
- marriage->h.xpos += dx;
- p = marriage->firstchild;
- while(p)
- {
- move_tree(p, dx);
- p = p->nextchild;
- }
- marriage = marriage->next;
- }
- /*
- * shift bb coords to match.
- */
- opts->bblx += dx;
- opts->bbux += dx;
- }
-
- /*
- * account for title at the top (normally bbuy would be
- * a positive number).
- */
- opts->bbuy = 0;
- }
-
- /*(
- **********************************************************************************
- *
- * Function: findmarriage1
- *
- *
- * Inputs:
- * id - the ID to look for
- *
- * Outputs:
- * marriage_t * - pointer to a marriage struct or NULL
- *
- * Error Handling:
- *
- *
- * Description:
- *
- * Finds the marriage in which one person has the ID code 'id'.
- *
- **********************************************************************************
- )*/
-
- marriage_t *findfirstmarriage(id_t id)
- {
- marriage_t *m, *found;
-
- if (id == NOID)
- {
- dbprintf(( "findfirstmarriage: no id\n"));
- return NULL;
- }
- m = mroot;
- found = NULL;
- while(m)
- {
- if ( ((m->husband != NULL) && idcmp(id, m->husband->id) ) ||
- ((m->wife != NULL) && idcmp(id, m->wife->id)) )
- {
- found = m;
- dbprintf(( "findfirstmarriage: found initial match for %lx\n", id));
- }
- m = m->nextmarriage;
- }
-
- if (found)
- {
- /*
- * go to the first marriage in this list
- */
- while(found->prev)
- {
- dbprintf(( "findfirstmarriage: found earlier match\n"));
- found = found->prev;
- }
- }
- else
- dbprintf(( "findfirstmarriage: no match found for %lx\n", id));
-
- return found;
- }
-
- /*(
- **********************************************************************************
- *
- * Function: findmarriage2
- *
- *
- * Inputs:
- * id - the ID to look for
- *
- * Outputs:
- * marriage_t * - pointer to a marriage struct or NULL
- *
- * Error Handling:
- *
- *
- * Description:
- *
- * Finds the marriage in which one person has the ID code 'id'.
- *
- **********************************************************************************
- )*/
-
- marriage_t *findmarriage2(id_t hid, id_t wid)
- {
- marriage_t *m;
-
- if (hid == NOID || wid == NOID)
- {
- dbprintf(( "findmarriage2: no id\n"));
- return NULL;
- }
- m = mroot;
- while(m)
- {
- if (((m->husband != NULL) && idcmp(hid, m->husband->id)) ||
- ((m->wife != NULL) && idcmp(wid, m->wife->id)))
- {
- dbprintf(( "findmarriage2: found match h%lx/w%lx\n", hid, wid));
- break;
- }
- m = m->nextmarriage;
- }
- return m;
- }
-
-
- /*(
- **********************************************************************************
- *
- * Function: findperson
- *
- *
- * Inputs:
- * id - person id code
- *
- * Outputs:
- * person_t * - pointer to a person record
- *
- * Error Handling:
- * Checks that id is non-null. returns NULL if
- * person not found.
- *
- * Description:
- *
- * Returns (a pointer to) the person record for the person who matches the
- * id code.
- *
- **********************************************************************************
- )*/
-
- person_t *findperson(id_t id)
- {
- person_t *p;
- p = proot;
-
- if (id == NULL)
- {
- dbprintf(( "findperson: no id\n"));
- return NULL;
- }
- while(p)
- {
- if (idcmp(id, p->id))
- {
- dbprintf(( "findperson: found match %lx\n", p->id));
- break;
- }
- p = p->nextperson;
- }
- return p;
- }
-
-
- /*(
- **********************************************************************************
- *
- * Function: show_generations
- *
- *
- * Inputs:
- * none.
- *
- * Outputs:
- * none.
- *
- * Description:
- *
- * Prints out the generations line-by-line, as they should appear on the plot but
- * in text form. Debugging aid only. Prints out both directions (should be the
- * same).
- *
- **********************************************************************************
- )*/
-
- #ifdef DEBUG
- static void show_generations()
- {
- pmheader_t *p;
- int i;
- dbprintf(("show generations: %d levels; left->right\n", nlevels));
- for (i = 0; i < nlevels; i++)
- {
- p = generation[i].first;
- dbprintf(("%d: ", i));
- while(p)
- {
- switch(p->type)
- {
- case HT_PERSON:
- dbprintf(("%s", ((person_t*)p)->firstname));
- break;
- case HT_MARRIAGE:
- dbprintf(("'%s / %s'", ((marriage_t*)p)->husband->firstname, ((marriage_t*)p)->wife->firstname));
- break;
- }
- p = p->right;
- if (p)
- dbprintf((" -> "));
- }
- dbprintf(("\n"));
- }
- dbprintf(("\nshow generations: %d levels; right->left\n", nlevels));
- for (i = 0; i < nlevels; i++)
- {
- p = generation[i].last;
- dbprintf(("%d: ", i));
- while(p)
- {
- switch(p->type)
- {
- case HT_PERSON:
- dbprintf(("%s", ((person_t*)p)->firstname));
- break;
- case HT_MARRIAGE:
- dbprintf(("'%s & %s'", ((marriage_t*)p)->husband->firstname, ((marriage_t*)p)->wife->firstname));
- break;
- }
- p = p->left;
- if (p)
- dbprintf((" <- "));
- }
- dbprintf(("\n"));
- }
- }
-
- static char *nameof(pmheader_t *this)
- {
- char buf[80];
-
- if (this)
- {
- switch(this->type)
- {
- case HT_PERSON:
- sprintf(buf, "\"%s\"", ((person_t*)this)->firstname );
- return strdup(buf);
-
- case HT_MARRIAGE:
- sprintf(buf, "'%s & %s'", ((marriage_t*)this)->husband->firstname,
- ((marriage_t*)this)->wife->firstname);
- return strdup(buf);
-
- default:
- return "unknown";
- }
- }
- else
- return "no-one";
- }
-
- #if CHECK_LINKS
- #define check_p_b(p, s) if (((long)(p) & 1) == 1) {dbprintf(("%s ptr error\n", s)); break;}
- #define check_pers(p, s) if ((p)->h.type != HT_PERSON) {dbprintf(("%s not a person\n", s)); break;}
- #define check_marr(p, s) if ((p)->h.type != HT_MARRIAGE) {dbprintf(("%s not a marriage\n", s)); break;}
-
- void check_links()
- {
- person_t *p;
- marriage_t *m;
-
- dbprintf(("check links ... "));
- m = mroot;
- while(m != NULL)
- {
- check_p_b(m, "m");
- check_marr(m, "m");
- check_p_b(m->h.left, "m->h.left");
- check_p_b(m->h.right, "m->h.right");
- check_p_b(m->nextmarriage, "m->nextmarriage");
- check_p_b(m->next, "m->next");
- check_p_b(m->prev, "m->prev");
- check_p_b(m->husband, "m->husband");
- check_p_b(m->wife, "m->wife");
- check_p_b(m->backlink, "m->backlink");
- check_p_b(m->firstchild, "m->firstchild");
- check_p_b(m->lastchild, "m->lastchild");
-
- check_pers(m->wife, "m->wife");
- check_pers(m->husband, "m->husband");
- if (m->backlink != NULL)
- check_marr(m->backlink, "m->backlink");
-
- m = m->nextmarriage;
- }
- dbprintf((" people ... \n"));
- p = proot;
- while(p != NULL)
- {
- check_p_b(p, "p");
- check_pers(p, "p");
- check_p_b(p->h.left, "p->h.left");
- check_p_b(p->h.right, "p->h.right");
- check_p_b(p->nextperson, "p->nextperson");
- check_p_b(p->parents, "p->parents");
- check_p_b(p->nextchild, "p->nextchild");
- check_p_b(p->lastchild, "p->lastchild");
- check_p_b(p->firstmarriage, "p->firstmarriage");
- check_p_b(p->lastmarriage, "p->lastmarriage");
-
- if (p->nextchild)
- check_pers(p->nextchild, "p->nextchild");
- if (p->lastchild)
- check_pers(p->lastchild, "p->lastchild");
-
- if (p->parents)
- check_marr(p->parents, "p->parents");
- if (p->firstmarriage)
- check_marr(p->firstmarriage, "p->firstmarriage");
- if (p->lastmarriage)
- check_marr(p->lastmarriage, "p->lastmarriage");
-
- p = p->nextperson;
- }
- dbprintf(("done\n"));
- }
- #endif
- #endif
- @
-
-
- 1.8
- log
- @Fixed up the code to deal correctly with multiple marriages.
- Added a number of debugging statements and removed some of
- the redundant code - set_left_links etc. replacing them with
- the mirror_right_links code. As a result, findleft_back()
- and findleft_forw() can go too.
- Major changes result from the fact that some pointers can now
- point at marriage_t's or person_t's.
- Finally, added a routine check_links to check that the pointer
- referenced are valid and, where possible to check, correct. This
- is conditional on CHECK_LINKS being defined, and is not currently
- called.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/03/26 11:28:03 $
- d11 1
- a11 1
- * $Revision: 1.7 $
- d16 13
- d173 1
- a173 2
- generation[0].first = (pmheader_t*)findperson(opts->startperson);
- generation[0].last = generation[0].first;
- d291 2
- d369 1
- a369 1
- child->lastmarriage->h.right = NULL;
- a572 1
- dbprintf(("%s, ", nameof(next)));
- @
-
-
- 1.7
- log
- @Included multiple-marriage support.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/03/10 21:28:26 $
- d11 1
- a11 1
- * $Revision: 1.6 $
- d16 3
- d41 1
- d56 2
- a57 5
- static person_t *findleft_back(marriage_t *marriage, int level);
- static person_t *findleft_forw(marriage_t *marriage, int level);
- static person_t *findright_back(marriage_t *marriage, int level);
- static person_t *findright_forw(marriage_t *marriage, int level);
- static void set_left_links(options_t *, marriage_t *, int);
- d62 18
- a79 1
- static void check_parents(person_t *person);
- d82 1
- a82 1
- *************************************************************
- d98 11
- a108 12
- * Calls the routines to format and output PostScript
- * statements which will draw the family tree described in the
- * opts array, using data from the mroot/proot lists.
- *
- * The tree is assumed to be a true tree - i.e. one root
- * node branching out to n leaf nodes.
- *
- * If the named 'outputfile' is 'con' this is taken as
- * a signal to write output to the standard output stream
- * instead of opening a new file.
- *
- *************************************************************
- d117 1
- a117 1
- if (strcmp(opts->outputfile, "con"))
- d160 1
- a160 1
- generation[0].first = findperson(opts->startperson);
- a162 1
- set_left_links(opts, startmarriage, 1);
- d164 5
- d170 6
- d181 8
- a188 1
- adjust_layout(outf, opts);
- d219 1
- d238 1
- a238 1
- *************************************************************
- d256 7
- a262 8
- * Determines the initial placement of the marriage(s)
- * connected to 'id' and those marriages made by their children.
- * This initial placement ignores issues of overlap; this is dealt
- * with later. The main element here is the general x placement,
- * calculation of y placement, and the setting up of various
- * values in the person_t and marriage_t structures.
- *
- *************************************************************
- d269 1
- a269 1
- person_t *child, *lastchild;
- d272 1
- a272 1
- dbprintf(( "\ndo_simple_layout: do layout at: %d,%d level: %d\n", x,y, level));
- d276 4
- a279 8
- dbprintf(( "do_simple_layout: set marriage @@ %d x %d.\n", x, y));
- marriage->xpos = x;
- marriage->ypos = y;
- /* already done?:
- * if (marriage->width == 0)
- * marriage->width = widthofmarriage(opts, marriage);
- */
- assert(marriage->width != 0);
- a287 1
- lastchild = NULL;
- d291 7
- a297 2
- child->firstmarriage = findfirstmarriage(child->id);
- m = child->firstmarriage;
- d300 3
- d304 5
- a308 5
- dbprintf(("do_simple_layout: setting backlink for child marriage %s & %s to marriage %s & %s\n",
- child->firstmarriage->husband->firstname, child->firstmarriage->wife->firstname,
- marriage->husband->firstname, marriage->wife->firstname));
- /* already done?: m->width = widthofmarriage(opts, m); */
- ptwidth += m->width;
- d317 10
- a326 5
- child->married = (child->firstmarriage != NULL);
- child->fullname = !streq(child->family, marriage->husband->family) ||
- child->married;
- child->width = widthof(opts, child);
- child->level = level + 1;
- d328 1
- d330 1
- a330 1
- * set up the level pointers.
- d332 6
- a337 2
- child->right = child->nextchild;
- child->left = lastchild;
- d339 19
- a357 1
- ptwidth += child->width;
- a358 2
- dbprintf(( "do_simple_layout: adding width for child %d\n", children));
- lastchild = child;
- d361 1
- d363 1
- a363 1
- marriage->level = level;
- d370 4
- a373 2
- ptwidth -= (pwidthof(marriage->firstchild, XP_FIRST) + pwidthof(marriage->lastchild, XP_FIRST)) / 2;
-
- d401 3
- a403 4
- child->xpos = startx;
- child->ypos = childy;
- dbprintf(( "do_simple_layout: child %s @@ %dx%d\n",
- child->firstname, startx, childy));
- d409 2
- a410 2
- m->xpos = startx;
- m->ypos = childy;
- d412 1
- a412 1
- startx += (m->width + m->next->width) / 2;
- d414 2
- a415 1
- startx += (m->width + pwidthof(child->nextchild, XP_FIRST)) / 2;
- d417 2
- a418 3
- dbprintf(( "do_simple_layout: marriage %s / %s @@ %dx%d, next: %d\n",
- m->husband->firstname, m->wife->firstname,
- m->xpos, m->ypos, startx));
- d423 2
- a424 1
- startx += (child->width + pwidthof(child->nextchild, XP_FIRST)) / 2;
- d439 1
- a439 1
- child->xpos, child->ypos, level+1);
- d446 3
- a449 1
- x += INCH;
- d456 1
- a456 1
- ***********************************************************************
- d471 5
- a475 5
- * Modifies the data structure by adding in the left and
- * right pointers for inter-marriage links. Assumes that do_simple_layout
- * has already been done.
- *
- ***********************************************************************
- d480 1
- a481 1
- marriage_t *savemarriage = marriage;
- d485 1
- a485 1
- while(marriage)
- d487 2
- a488 3
- dbprintf(( "do_layout_part2: found marriage.\n"));
-
- if (marriage->children > 0)
- d490 1
- a490 2
- child = marriage->firstchild;
- while(child != NULL)
- d492 1
- a492 5
- if (child->married)
- {
- do_layout_part2(opts, child->firstmarriage, level+1);
- }
- child = child->nextchild;
- d494 1
- a495 3
- dbprintf(( "do_layout_part2: finished marriage.\n"));
-
- marriage = marriage->next;
- d502 1
- a502 5
- marriage = savemarriage;
- while(marriage)
- {
- dbprintf(( "do_layout_part2: filling links for marriage %s & %s.\n",
- marriage->husband->firstname,marriage->wife->firstname));
- d504 2
- a505 14
- child = findleft_back(marriage, level + 1);
- dbprintf(("do_layout_part2: findleft lev %d returns %s, firstchild: %s\n",
- level+1, child ? child->firstname : "nothing",
- marriage->firstchild ? marriage->firstchild->firstname : "nothing"));
-
- if (marriage->firstchild)
- marriage->firstchild->left = child;
-
- child = findright_back(marriage, level + 1);
- dbprintf(("do_layout_part2: findright lev %d returns %s, lastchild: %s\n",
- level+1, child ? child->firstname : "nothing",
- marriage->lastchild ? marriage->lastchild->firstname : "nothing"));
- if (marriage->lastchild)
- marriage->lastchild->right = child;
- d507 1
- a507 1
- dbprintf(( "do_layout_part2: finished links for marriage\n"));
- d509 6
- a514 4
- marriage = marriage->next;
- }
-
- dbprintf(( "do_layout_part2: finished level %d layout.\n", level));
- d518 1
- a518 1
- ***********************************************************************
- d520 1
- a520 1
- * Function: find_boundingbox
- d524 1
- a524 3
- * opts - global options structure
- * id - id code identifying the initial point
- * level - generation/recursion level
- d531 2
- a532 1
- *
- d534 1
- a534 1
- ***********************************************************************
- d537 6
- a542 2
- #define set_low(var, val) {if ((var) > (val)) (var) = (val); }
- #define set_high(var, val) {if ((var) < (val)) (var) = (val); }
- d544 5
- a548 4
- static void find_boundingbox(options_t *opts, marriage_t *marriage)
- {
- person_t *p;
- while (marriage)
- d550 1
- a550 3
- dbprintf(("find_boundingbox: marriage %s & %s: ",
- marriage->husband->firstname,
- marriage->wife->firstname));
- d552 3
- a554 6
- set_low(opts->bbly, marriage->ypos);
- set_high(opts->bbuy, marriage->ypos);
- set_low(opts->bblx, marriage->xpos - marriage->width / 2);
- set_high(opts->bbux, marriage->xpos + marriage->width / 2);
-
- if (marriage->children > 0)
- d556 1
- a556 3
- dbprintf(("child %s\n", marriage->firstchild->firstname));
- p = marriage->firstchild;
- while(p)
- d558 4
- a561 12
- if (p->married)
- {
- find_boundingbox(opts, p->firstmarriage);
- }
- else
- {
- set_low(opts->bbly, p->ypos);
- set_high(opts->bbuy, p->ypos);
- set_low(opts->bblx, p->xpos - p->width / 2);
- set_high(opts->bbux, p->xpos + p->width / 2);
- }
- p = p->nextchild;
- d563 1
- a564 4
- else
- dbprintf(("no children\n"));
-
- marriage = marriage->next;
- d566 2
- d571 1
- a571 1
- ***********************************************************************
- d573 1
- a573 1
- * Function: set_left_links
- a584 4
- *
- * Sets up generation[] array by scanning through the tree
- * looking for leftmost people on a level which hasn't been defined yet.
- * When found, the left pointer in the array is set to this person.
- d586 9
- a594 1
- ***********************************************************************
- d597 4
- a600 1
- static void set_left_links(options_t *opts, marriage_t *marriage, int level)
- a602 4
-
- if (marriage == NULL)
- return;
-
- d605 6
- a610 4
- dbprintf(("set_left_links: marriage %s & %s level %d: ",
- marriage->husband->firstname,
- marriage->wife->firstname,
- level));
- a611 13
- /*
- * operate the generation array on a first-come-first-served
- * basis, so we get the end points. We actually scan the whole
- * tree, though.
- */
- if (generation[level].first == NULL)
- {
- generation[level].first = marriage->firstchild;
- dbprintf(("FIRST: "));
- }
- if (nlevels < level)
- nlevels = level;
-
- d614 1
- a614 3
- dbprintf(("child %s (lev: %d)\n",
- marriage->firstchild->firstname,
- marriage->firstchild->level));
- d620 8
- a627 1
- set_left_links(opts, p->firstmarriage, level+1);
- d634 1
- a634 1
-
- d638 2
- d642 1
- a642 1
- ***********************************************************************
- d657 5
- a661 5
- * Sets up generation[] array by scanning through the tree
- * looking for rightmost people on a level which hasn't been defined yet.
- * When found, the right pointer in the array is set to this person.
- *
- ***********************************************************************
- a670 6
- /*
- * make sure we're at the end of this list of marriages.
- */
- while(marriage->next != NULL)
- marriage = marriage->next;
-
- d673 1
- a673 3
- dbprintf(("set_right_links: marriage %s & %s level %d: ",
- marriage->husband->firstname, marriage->wife->firstname,
- level));
- d680 1
- a680 1
- if (generation[level].last == NULL)
- d682 2
- a683 2
- generation[level].last = marriage->lastchild;
- dbprintf(("LAST: "));
- d685 2
- a686 2
- if (nlevels < level)
- nlevels = level;
- d691 3
- a693 3
- marriage->firstchild->firstname,
- marriage->firstchild->level));
- p = marriage->lastchild;
- d698 1
- a698 1
- set_right_links(opts, p->lastmarriage, level+1);
- d700 1
- a700 1
- p = p->lastchild;
- d706 1
- a706 1
- marriage = marriage->prev;
- d711 1
- a711 1
- *************************************************************
- d718 2
- a719 2
- * id - the ID of the person to start at, who should be
- * married.
- d729 2
- a730 3
- * This routine takes the initial positions assigned by
- * the routine do_simple_layout and adjusts the positions such that
- * people do not overlap.
- d732 12
- a743 1
- *************************************************************
- d746 5
- a750 1
- void adjust_layout(FILE *outf, options_t *opts)
- d752 1
- a752 1
- int c, gen, dx, moved;
- d754 5
- a758 1
- person_t *person, *lastperson;
- d762 1
- a762 1
- c = 0;
- d766 1
- a766 1
- for(gen = 0; gen <= nlevels; gen++)
- d768 3
- a770 5
- person = generation[gen].first;
- lastperson = NULL;
- dbprintf(("adjust_layout: generation %d (starts with %s %s, right %s)\n",
- gen, person->firstname, person->family,
- person->right ? person->right->firstname : "no-one"));
- d772 1
- a772 1
- while(person)
- d774 1
- a774 1
- if (lastperson != NULL)
- d776 2
- d783 7
- a789 2
- dx = (xposof(person, XP_FIRST) - xposof(lastperson, XP_LAST));
- dx -= ((pwidthof(person, XP_FIRST) + pwidthof(lastperson, XP_LAST) ) / 2 );
- d791 2
- a792 3
- dbprintf(("examining %s & %s (%d vs %d), dx = %d\n",
- lastperson->firstname, person->firstname,
- xposof(lastperson, XP_LAST), xposof(person, XP_FIRST), dx));
- a802 1
-
- d805 2
- a806 2
- p2 = person;
- while(p2)
- d808 15
- a822 2
- move_tree(p2, dx);
- p2 = p2->nextchild;
- a823 1
- move_parents = TRUE;
- d825 1
- a825 1
- else if (dx > 1 && lastperson->nextchild == person)
- d831 1
- a831 1
- if (lastperson->lastchild == NULL && !lastperson->married)
- d834 2
- a835 2
- lastperson->firstname, person->firstname, dx));
- lastperson->xpos += dx;
- d840 1
- a840 1
- if (person->nextchild == NULL && !person->married)
- d843 2
- a844 2
- person->firstname, lastperson->firstname, dx));
- person->xpos -= dx;
- d851 1
- a851 1
- if (lastperson->nextchild == person)
- d857 1
- a857 1
- if (person->nextchild != NULL && !person->married)
- d862 3
- a864 3
- nc = person->nextchild;
- dx2 = xposof(nc, XP_FIRST) - person->xpos;
- dx2 -= ((person->width + pwidthof(nc, XP_FIRST)) / 2 );
- d867 1
- a867 1
- lastperson->firstname, dx, person->firstname, dx2, nc->firstname, diff / 2));
- d871 2
- a872 2
- person->firstname, diff / 2));
- person->xpos += diff / 2;
- d879 2
- a880 2
- person->firstname, diff / 2));
- person->xpos += diff / 2;
- a884 5
- else
- {
- dbprintf(("adjust_layout: cannot centre %s %s\n",
- person->firstname, person->family));
- }
- d888 1
- a888 4
- if (person->parents)
- {
- check_parents(person);
- }
- d893 2
- a894 2
- lastperson = person;
- person = person->right;
- d901 7
- a907 5
- c++;
- /* print_tree(outf, opts, findfirstmarriage(opts,opts->startperson)); */
- /* fprintf(outf, "showpage\n"); */
- } while(moved && c < MAX_ADJUSTS);
- if (c == MAX_ADJUSTS)
- d911 1
- a911 1
- fprintf(stderr, "adjust_layout: took %d tries to adjust layout.\n", c);
- d913 4
- d919 28
- a946 1
- static void check_parents(person_t *person)
- d949 12
- a960 1
- marriage_t *m = person->parents;
- d964 3
- a966 16
- dbprintf(("check_parents: checking marriage %s / %s\n",
- m->husband->firstname, m->wife->firstname));
- /*
- * get range of X used by children of this marriage...
- */
- fc = xposof(m->lastchild, XP_FIRST);
- lc = xposof(m->firstchild, XP_FIRST);
- dxp = fc - lc;
- if (dxp < 0)
- dxp = - dxp;
- xp = fc + (dxp / 2);
-
- /*
- * and check that the marriage is decently centred.
- */
- if (abs(xp - m->xpos) > 1)
- d968 19
- a986 5
- dbprintf(("check_parents: child %s of parents @@ %d / %d\n",
- person->firstname, fc, lc));
- dbprintf(("check_parents: moving parents %s & %s by %d to %d\n",
- m->husband->firstname, m->wife->firstname, xp - m->xpos, xp));
- m->xpos = xp;
- d992 32
- d1026 1
- a1026 1
- *************************************************************
- d1043 4
- a1046 4
- * Moves the tree based at 'marriage' by an ammount 'dx'
- * in the X direction. No effect in the Y direction.
- *
- *************************************************************
- d1062 1
- a1062 1
- marriage->xpos += dx;
- d1074 1
- a1074 2
- person->xpos += dx;
-
- d1077 3
- a1079 20
- /*(
- *************************************************************
- *
- * Function: widthof
- *
- *
- * Inputs:
- * opts - global options
- * pers - pointer to a person record.
- *
- * Outputs:
- * int -width in PS units (points) of the printed
- * version of the person.
- *
- * Description:
- *
- * return the width required to print 'person'
- *
- *************************************************************
- )*/
- d1081 1
- a1081 4
- int widthof(options_t *opts, person_t *pers)
- {
- int w, namew, datew;
- char bufn[128], bufd[128];
- d1083 1
- a1083 1
- if (pers->fullname)
- d1085 9
- a1093 3
- strcpy(bufn, pers->firstname);
- strcat(bufn, " ");
- strcat(bufn, pers->family);
- a1094 14
- else
- strcpy(bufn, pers->firstname);
-
- namew = (int)stringwidth(&opts->personfont, opts->afmconst, bufn);
-
- datefmt(bufd, &pers->born, &pers->died);
- datew = (int)stringwidth(&opts->datefont, opts->afmconst, bufd);
-
- dbprintf(("widthof: person %s / %s returns %d / %d\n", bufn, bufd, namew, datew));
-
- if (namew > datew)
- w = namew + opts->tree_gap;
- else
- w = datew + opts->tree_gap;
- a1095 4
- dbprintf(( "widthof: %s width of \"%s\" is \t%d.\n",
- (pers->fullname)?"full":"short", pers->firstname, w));
-
- return w;
- a1096 22
-
- int widthofmarriage(options_t *opts, marriage_t *marriage)
- {
- int w1, w2, w3;
-
- w1 = widthof(opts, marriage->husband);
- w2 = widthof(opts, marriage->wife);
-
- w3 = (int)stringwidth(&opts->symfont, opts->afmconst, "x");
- if (marriage->when.known)
- w3 += (int)stringwidth(&opts->datefont, opts->afmconst, date2string(&marriage->when));
-
- if (w1 < w2)
- w1 = w2;
- if (w1 < w3)
- w1 = w3;
-
- dbprintf(("widthofmarriage: return %d for marriage width\n", w1));
-
- return w1;
- }
-
- d1098 1
- a1098 1
- ***********************************************************************
- d1100 1
- a1100 1
- * Function: findleft_back
- d1116 13
- a1128 14
- * Searches for the next person at the desired level left
- * from the current marriage. This search may proceed back as far as is
- * necessary (or possible). This routine uses findleft_forw to search
- * forwards (younger) from given start points.
- *
- * The search uses the backlink which was constrcted when
- * the initial layout was done, as the mapping from child to parent is
- * one-to-many so it cannot be searched for.
- *
- * The primary use for this routine is in the construction
- * of the left/right links which link up members of the same generation
- * in order.
- *
- ***********************************************************************
- d1131 1
- a1131 1
- static person_t *findleft_back(marriage_t *marriage, int level)
- d1133 3
- a1135 6
- person_t *p, *q;
- marriage_t *m;
-
- dbprintf(("findleft_back: look for marriage from %s / %s at level %d (backlink %s)\n",
- marriage->husband->firstname, marriage->wife->firstname, level,
- marriage->backlink ? "present" : "not present"));
- d1139 1
- a1139 1
- dbprintf(("findleft_back: no marriage!!.\n"));
- d1142 2
- a1143 1
- if (marriage->backlink == NULL)
- d1145 1
- a1145 1
- dbprintf(("findleft_back: no backlink.\n"));
- d1149 1
- a1149 2
- m = marriage->backlink;
- if (m->firstchild != marriage->husband && m->firstchild != marriage->wife)
- d1151 6
- a1156 16
- /*
- * marriage not first child - try some of the children.
- *
- * First find out which parent is the child of the marriage given.
- */
- p = m->firstchild;
- while(p != NULL && p != marriage->husband && p != marriage->wife)
- {
- p = p->nextchild;
- }
-
- /*
- * p is should now point to the child of the older marriage who is
- * a parent in this one. (p == NULL) is an error.
- */
- while((p = p->lastchild))
- a1157 1
-
- d1159 3
- a1161 1
- * if the level's match, this is it!
- d1163 2
- a1164 1
- if (p->level == level)
- d1166 1
- a1166 3
- dbprintf(("findleft_back: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return p;
- d1170 2
- a1171 2
- * levels didn't match. Try following this marriage...
- * (p->level < level implies that we are too old still)
- d1173 3
- a1175 1
- if (p->level < level && p->married)
- d1177 31
- a1207 3
- q = findleft_forw(p->firstmarriage, level);
- if (q)
- return q;
- d1210 4
- d1216 4
- a1219 1
- return findleft_back(m, level);
- d1223 1
- a1223 1
- ***********************************************************************
- d1225 1
- a1225 1
- * Function: findleft_forw
- d1240 4
- a1243 5
- * Finds the next person at the desired level. The match
- * condition required that the person found is the leftmost person possible
- * from the given start position.
- *
- ***********************************************************************
- d1246 1
- a1246 1
- static person_t *findleft_forw(marriage_t *marriage, int level)
- d1248 2
- a1249 1
- person_t *p, *q, *r;
- d1252 1
- a1252 1
- dbprintf(("findleft_forw: look for marriage from %s / %s at level %d\n",
- d1259 1
- a1259 2
- p = marriage->lastchild;
- while(p)
- d1261 2
- a1262 1
- if (p->level == level)
- d1264 6
- a1269 4
- dbprintf(("findleft_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return p;
- }
- d1271 1
- a1271 10
- if (p->married)
- {
- /*
- * look backwards through the person's children
- * (if any) & check. If any are married, recurse to
- * check them too.
- */
- m = p->firstmarriage;
- q = m->lastchild;
- while(q)
- d1274 2
- a1275 1
- * found!
- d1277 2
- a1278 1
- if (q->level == level)
- d1280 12
- a1291 4
- dbprintf(("findleft_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return q;
- }
- d1293 10
- a1302 7
- if (q->married)
- {
- r = findleft_forw(q->firstmarriage, level);
- if (r)
- {
- dbprintf(("findleft_forw: already found, returning...\n"));
- return r;
- d1304 1
- a1305 2
-
- q = q->lastchild;
- d1307 3
- a1309 34
- }
- p = p->lastchild;
- }
-
- dbprintf(("findleft_forw: nothing found.\n"));
- return NULL;
- }
-
- /*(
- ***********************************************************************
- *
- * Function:
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Error Handling:
- *
- *
- * Description:
- *
- *
- *
- ***********************************************************************
- )*/
-
- static person_t *findright_back(marriage_t *marriage, int level)
- {
- person_t *p, *q;
- marriage_t *m;
- a1310 26
- dbprintf(("findright_back: look for marriage from %s / %s at level %d (backlink %s)\n",
- marriage->husband->firstname, marriage->wife->firstname, level,
- marriage->backlink ? "present" : "not present"));
-
- if (marriage == NULL)
- {
- dbprintf(("findright_back: no marriage!!.\n"));
- return NULL;
- }
- if (marriage->backlink == NULL)
- {
- dbprintf(("findright_back: no backlink.\n"));
- return NULL;
- }
-
- m = marriage->backlink;
- if (m->lastchild != marriage->husband && m->lastchild != marriage->wife)
- {
- /*
- * marriage not first child - try some of the children.
- *
- * First find out which parent is the child of the marriage given.
- */
- p = m->firstchild;
- while(p != NULL && p != marriage->husband && p != marriage->wife)
- {
- d1313 1
- d1315 1
- a1315 28
- /*
- * p is should now point to the child of the older marriage who is
- * a parent in this one. (p == NULL) is an error.
- */
- while((p = p->nextchild))
- {
-
- /*
- * if the level's match, this is it!
- */
- if (p->level == level)
- {
- dbprintf(("findright_back: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return p;
- }
-
- /*
- * levels didn't match. Try following this marriage...
- * (p->level < level implies that we are too old still)
- */
- if (p->level < level && p->married)
- {
- q = findright_forw(p->firstmarriage, level);
- if (q)
- return q;
- }
- }
- d1318 2
- a1319 1
- return findright_back(m, level);
- d1323 1
- a1323 1
- ***********************************************************************
- d1325 1
- a1325 1
- * Function:
- d1329 2
- a1330 1
- *
- d1333 1
- a1333 4
- *
- *
- * Error Handling:
- *
- d1337 6
- a1342 3
- *
- *
- ***********************************************************************
- d1345 1
- a1345 2
-
- static person_t *findright_forw(marriage_t *marriage, int level)
- d1347 1
- a1347 14
- person_t *p, *q, *r;
- marriage_t *m;
-
- dbprintf(("findright_forw: look for marriage from %s / %s at level %d\n",
- marriage->husband->firstname, marriage->wife->firstname, level));
-
- if (marriage == NULL)
- {
- dbprintf(("findright_forw: no marriage!!.\n"));
- return NULL;
- }
-
- p = marriage->firstchild;
- while(p)
- d1349 1
- a1349 8
- if (p->level == level)
- {
- dbprintf(("findright_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return p;
- }
-
- if (p->married)
- d1351 2
- a1352 13
- /*
- * look backwards through the person's children
- * (if any) & check. If any are married, recurse to
- * check them too.
- */
- m = p->firstmarriage;
- q = m->firstchild;
- while(q)
- {
- /*
- * found!
- */
- if (q->level == level)
- d1354 4
- a1357 3
- dbprintf(("findright_forw: found %s %s at level %d\n",
- p->firstname, p->family, p->level));
- return q;
- d1359 2
- d1362 2
- a1363 12
- if (q->married)
- {
- r = findright_forw(q->firstmarriage, level);
- if (r)
- {
- dbprintf(("findright_forw: already found, returning...\n"));
- return r;
- }
- }
-
- q = q->nextchild;
- }
- a1364 1
- p = p->nextchild;
- d1366 2
- a1367 3
-
- dbprintf(("findright_forw: nothing found.\n"));
- return NULL;
- d1371 1
- a1371 1
- ***********************************************************************
- d1373 1
- a1373 1
- * Function: xposof
- d1381 1
- a1381 1
- * int - xpos value of a person/marriage
- d1385 7
- a1391 7
- * Returns the xpos value for person. If person not married this is
- * just the xpos of the person. For marriages, because a person may have
- * more than one location, 'spec' is used to determine which of the
- * posssible marriages to return the position of. Currently, only the first
- * and last in the list are needed.
- *
- ***********************************************************************
- d1394 1
- a1394 1
- int xposof(person_t *p, enum xpspec_t spec)
- d1398 1
- a1398 1
- if (p->married)
- d1400 13
- a1412 4
- if (spec == XP_FIRST)
- return p->firstmarriage->xpos;
- else
- return p->lastmarriage->xpos;
- a1413 2
- else
- return p->xpos;
- d1415 1
- d1419 1
- d1421 1
- a1421 1
- ***********************************************************************
- d1423 1
- a1423 1
- * Function: pwidthof
- d1435 6
- a1440 7
- * Returns the xpos value for person. If person not married this is
- * just the xpos of the person. For marriages, because a person may have
- * more than one location, 'spec' is used to determine which of the
- * posssible marriages to return the position of. Currently, only the first
- * and last in the list are needed.
- *
- ***********************************************************************
- d1443 1
- a1443 1
- int pwidthof(person_t *p, enum xpspec_t spec)
- d1447 1
- a1447 1
- if (p->married)
- d1449 13
- a1461 4
- if (spec == XP_FIRST)
- return p->firstmarriage->width;
- else
- return p->lastmarriage->width;
- a1462 2
- else
- return p->width;
- d1464 2
- a1465 1
- return 0;
- d1469 1
- a1469 1
- ***********************************************************************
- d1479 1
- a1479 4
- *
- *
- * Error Handling:
- *
- d1483 5
- a1487 6
- * Calls find_boundingbox to calculate the area used by the
- * chart. It then forces the chart's left egde to be visible on the first
- * page printed by adding any negative offset to the x coords of the
- * chart's elements.
- *
- ***********************************************************************
- d1510 1
- a1510 1
- marriage->xpos += dx;
- d1534 1
- a1534 1
- *************************************************************
- d1550 1
- a1550 2
- * Finds the marriage in which one person has the
- * ID code 'id'.
- d1552 1
- a1552 1
- *************************************************************
- d1572 1
- a1572 1
- dbprintf(( "findfirstmarriage: found initial match %lx\n", id));
- d1588 2
- d1595 1
- a1595 1
- *************************************************************
- d1611 1
- a1611 2
- * Finds the marriage in which one person has the
- * ID code 'id'.
- d1613 1
- a1613 1
- *************************************************************
- d1639 1
- d1641 1
- a1641 1
- *************************************************************
- d1658 2
- a1659 2
- * Returns (a pointer to) the person record for
- * the person who matches the id code.
- d1661 1
- a1661 1
- *************************************************************
- d1686 165
- @
-
-
- 1.6
- log
- @Multiple pages working!
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/03/07 13:00:31 $
- d11 1
- a11 1
- * $Revision: 1.5 $
- d16 3
- d41 2
- d46 4
- d56 3
- a58 3
- static void set_left_links(options_t *, id_t, int);
- static void set_right_links(options_t *, id_t, int);
- static void do_layout_part2(options_t *opts, id_t id, int level);
- d60 2
- a61 1
- static void normalise_area(options_t *opts);
- d97 2
- a98 1
- int i;
- d112 6
- d119 1
- a119 1
- generation[i].first = generation[i].last = 0;
- a120 2
- dbprintf(("\n----------------------------------- do_prolog ------------------------------------------------------\n"));
-
- d122 1
- d126 1
- a126 2
- do_simple_layout(opts, opts->startperson, (opts->pagewidth - opts->rmargin)/2,
- opts->titlefont.linespc + 3*opts->personfont.linespc, 0);
- d130 6
- a135 1
- do_layout_part2(opts, opts->startperson, 0);
- d143 5
- a147 2
- set_left_links(opts, opts->startperson, 0);
- set_right_links(opts, opts->startperson, 0);
- d154 1
- a154 1
- adjust_layout(outf, opts, opts->startperson);
- d159 3
- a161 1
- * get the bounding box for PS.
- d163 1
- a163 1
- normalise_area(opts);
- d165 2
- d168 1
- a168 1
- * print out the prolog stuff
- d177 1
- a177 1
- do_title(outf, opts);
- d184 1
- a184 1
- print_tree(outf, opts, opts->startperson);
- d198 2
- d231 1
- a231 1
- void do_simple_layout(options_t *opts, id_t id, int x, int y, int level)
- d236 1
- a236 1
- marriage_t *marriage;
- d238 1
- a238 1
- dbprintf(( "\ndo_simple_layout: do layout for ID %lx at: %d,%d level: %d\n", id, x,y, level));
- a239 1
- marriage = findmarriage1(id);
- d242 1
- a242 1
- dbprintf(( "do_simple_layout: found marriage.\n"));
- d245 5
- d252 2
- a253 1
- * work out how many children there are
- d262 3
- a264 2
- child->firstmarriage = findmarriage1(child->id);
- if (child->firstmarriage)
- d266 1
- a266 1
- child->firstmarriage->backlink = marriage;
- d268 11
- a278 4
- child->firstmarriage->husband->firstname,
- child->firstmarriage->wife->firstname,
- marriage->husband->firstname,
- marriage->wife->firstname));
- d306 1
- a306 1
- ptwidth -= (marriage->firstchild->width + marriage->lastchild->width) / 2;
- d330 1
- a330 1
- * have a go at placing the children.
- d339 20
- a358 1
- startx += (child->width + child->nextchild->width) / 2;
- d370 1
- a370 1
- * these positions should be 'plain'
- d372 2
- a373 2
- do_simple_layout(opts, child->id,
- child->xpos, child->ypos, level+1);
- d384 1
- a384 1
- dbprintf(( "do_simple_layout: finished simple layout for ID %lx.\n", id));
- d410 1
- a410 1
- static void do_layout_part2(options_t *opts, id_t id, int level)
- d413 1
- a413 1
- marriage_t *marriage;
- d415 1
- a415 1
- dbprintf(( "\ndo_layout_part2: ID: %lx, level %d\n", id, level));
- a416 1
- marriage = findmarriage1(id);
- d428 1
- a428 1
- do_layout_part2(opts, child->id, level+1);
- d442 1
- a442 1
- marriage = findmarriage1(id);
- d448 3
- a450 3
- child = findleftat(marriage, level + 1);
- dbprintf(("do_layout_part2: findleft lev %d returns %s, firstchild: %s\n", level+1,
- child ? child->firstname : "nothing",
- d456 3
- a458 3
- child = findrightat(marriage, level + 1);
- dbprintf(("do_layout_part2: findright lev %d returns %s, lastchild: %s\n", level+1,
- child ? child->firstname : "nothing",
- d463 1
- a463 1
- dbprintf(( "do_layout_part2: finished links for marriage %lx.\n", id));
- d468 1
- a468 1
- dbprintf(( "do_layout_part2: finished simple layout for ID %lx.\n", id));
- d498 1
- a498 1
- if (marriage)
- d531 2
- d559 1
- a559 1
- static void set_left_links(options_t *opts, id_t id, int level)
- d562 3
- a564 1
- marriage_t *marriage;
- d566 1
- a566 2
- marriage = findmarriage1(id);
- if (marriage)
- d579 1
- d581 2
- d596 1
- a596 2
- set_left_links(opts, p->id, level+1);
- break;
- d603 2
- d611 1
- a611 1
- * Function: set_left_links
- d625 1
- a625 1
- * looking for leftmost people on a level which hasn't been defined yet.
- d631 1
- a631 1
- static void set_right_links(options_t *opts, id_t id, int level)
- d634 9
- a642 1
- marriage_t *marriage;
- d644 1
- a644 2
- marriage = findmarriage1(id);
- if (marriage)
- d647 1
- a647 2
- marriage->husband->firstname,
- marriage->wife->firstname,
- d656 1
- d658 2
- d673 1
- a673 2
- set_right_links(opts, p->id, level+1);
- break;
- d680 2
- d711 1
- a711 1
- void adjust_layout(FILE *outf, options_t *opts, id_t id)
- d713 1
- a713 1
- int c, i, dx, moved;
- d723 1
- a723 1
- for(i = 0; i <= nlevels; i++)
- d725 1
- a725 1
- person = generation[i].first;
- d727 2
- a728 2
- dbprintf(("adjust_layout: generation %d (starts with %s %s, right %s)\n", i,
- person->firstname, person->family,
- d740 2
- a741 2
- dx = (xposof(person) - xposof(lastperson));
- dx -= ((lastperson->width + person->width) / 2 );
- d745 1
- a745 1
- xposof(lastperson), xposof(person), dx));
- d805 2
- a806 2
- dx2 = xposof(nc) - xposof(person);
- dx2 -= ((person->width + nc->width) / 2 );
- d837 1
- a837 10
- int dxp, xp;
- marriage_t *m = person->parents;
- dxp = xposof(m->lastchild) - xposof(m->firstchild);
- if (dxp < 0)
- dxp = - dxp;
- xp = xposof(m->firstchild) + (dxp / 2);
- dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d to %d\n",
- person->firstname,person->parents->husband->firstname,
- person->parents->wife->firstname, xp - m->xpos, xp));
- m->xpos = xp;
- d852 1
- a852 1
- /* print_tree(outf, opts, opts->startperson); */
- d863 35
- d933 1
- a933 4
- marriage->xpos += dx;
-
- child = marriage->firstchild;
- while(child)
- d935 9
- a943 2
- move_tree(child, dx);
- child = child->nextchild;
- d958 2
- a959 1
- *
- d962 2
- a963 4
- *
- *
- * Error Handling:
- *
- d974 2
- a975 3
- int w;
- int l, ld;
- char *s;
- d979 3
- a981 2
- l = strlen(pers->family);
- l += strlen(pers->firstname) + 1;
- d984 30
- a1013 3
- {
- l = strlen(pers->firstname);
- }
- d1015 4
- a1018 10
- /*
- * account for the date - see functions in print.c for
- * date formatting. generally:
- * (<born> - <died>) where <born> & <died> are like
- * 27-May-74 or blank
- */
- s = date2string(&pers->born);
- ld = strlen(s);
- s = date2string(&pers->died);
- ld += strlen(s) + 5;
- d1020 1
- a1020 5
- if (ld > l)
- {
- dbprintf(( "widthof: date %d longer than name %d, using date len.\n", ld, l));
- l = ld;
- }
- d1022 1
- a1022 6
- w = (opts->personfont.size * l) * opts->afmconst;
- w = w + opts->tree_gap;
-
- dbprintf(( "widthof: %s width of \"%s\" is \t%d (%dc).\n",
- (pers->fullname)?"full":"short", pers->firstname, w, l));
- return w;
- d1028 1
- a1028 1
- * Function:
- d1032 2
- a1033 1
- *
- d1036 1
- a1036 1
- *
- d1039 2
- a1040 1
- *
- d1044 12
- a1055 1
- *
- a1059 5
- person_t *findleftat(marriage_t *marriage, int level)
- {
- return findleft_back(marriage, level);
- }
-
- d1130 1
- a1130 1
- * Function:
- d1134 2
- a1135 1
- *
- d1138 1
- a1138 1
- *
- d1145 3
- a1147 1
- *
- a1236 5
- person_t *findrightat(marriage_t *marriage, int level)
- {
- return findright_back(marriage, level);
- }
-
- d1395 1
- a1395 1
- * Function:
- d1399 2
- a1400 1
- *
- d1403 1
- a1403 4
- *
- *
- * Error Handling:
- *
- d1407 5
- a1411 1
- *
- d1416 1
- a1416 1
- int xposof(person_t *p)
- d1421 6
- a1426 1
- return p->firstmarriage->xpos;
- d1436 1
- a1436 1
- * Function:
- d1440 2
- a1441 1
- *
- d1444 1
- a1444 1
- *
- a1445 3
- * Error Handling:
- *
- *
- d1448 5
- a1452 1
- *
- d1457 1
- a1457 1
- int yposof(person_t *p)
- d1462 6
- a1467 1
- return p->firstmarriage->ypos;
- d1469 1
- a1469 1
- return p->ypos;
- d1477 1
- a1477 1
- * Function:
- d1481 2
- a1482 1
- *
- d1492 4
- a1495 1
- *
- d1500 1
- a1500 1
- static void normalise_area(options_t *opts)
- a1501 1
- marriage_t *m = findmarriage1(opts->startperson);
- d1512 1
- a1512 1
- find_boundingbox(opts, m);
- d1518 1
- a1518 3
- m->xpos += dx;
- p = m->firstchild;
- while(p)
- d1520 8
- a1527 2
- move_tree(p, dx);
- p = p->nextchild;
- d1537 2
- a1538 1
- * account for title at the top.
- d1542 153
- @
-
-
- 1.5
- log
- @Reduced stringwidth const.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/03/07 12:44:14 $
- d11 1
- a11 1
- * $Revision: 1.4 $
- d16 3
- d41 1
- a41 2
- #define TREE_GAP 10
- #define MAX_ADJUSTS 20
- a105 12
- /*
- * print out the prolog stuff
- */
- do_prolog(outf, opts);
-
- dbprintf(("\n----------------------------------- do_title -------------------------------------------------------\n"));
-
- /*
- * put a title on the page
- */
- do_title(outf, opts);
-
- d140 12
- d637 1
- d688 1
- a688 13
- if (person->parents)
- {
- int dxp, xp;
- marriage_t *m = person->parents;
- dxp = xposof(m->lastchild) - xposof(m->firstchild);
- if (dxp < 0)
- dxp = - dxp;
- xp = xposof(m->firstchild) + (dxp / 2);
- dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d to %d\n",
- person->firstname,person->parents->husband->firstname,
- person->parents->wife->firstname, xp - m->xpos, xp));
- m->xpos = xp;
- }
- d690 1
- a690 1
- else if (dx > TREE_GAP && lastperson->nextchild == person)
- d703 1
- d712 1
- d715 2
- a716 2
- #if 0
- else if (lastperson->nextchild == person)
- d725 1
- a725 1
- int dx2, dx3;
- d730 4
- a733 3
- dx3 = dx2 - dx;
- dbprintf(("adjust_layout: check centering: dx2: %d, dx3: %d\n", dx2, dx3));
- if (dx3 > TREE_GAP)
- d736 2
- a737 2
- person->firstname, dx3 / 2));
- person->xpos += dx3 / 2;
- d741 1
- a741 1
- else if (dx3 < -TREE_GAP)
- d744 2
- a745 2
- person->firstname, dx3 / 2));
- person->xpos += dx3 / 2;
- d750 22
- a772 1
- #endif
- d791 1
- d894 2
- d897 1
- d899 2
- a900 2
- w = (opts->personfont.size * l) / 1.48;
- w = w + TREE_GAP;
- d907 21
- d1001 21
- d1086 21
- d1180 22
- d1268 21
- d1302 21
- d1336 21
- @
-
-
- 1.4
- log
- @Passed on as first Version.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/03/01 23:23:01 $
- d11 1
- a11 1
- * $Revision: 1.3 $
- d16 3
- d880 1
- a880 1
- w = (opts->personfont.size * l) / 1.6;
- @
-
-
- 1.3
- log
- @changes to complete layered adjustment of position
- including auto-centering of parents.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/02/27 19:32:55 $
- d11 1
- a11 1
- * $Revision: 1.2 $
- d16 4
- d36 1
- d45 2
- d140 7
- d409 63
- a685 1
-
- a689 1
-
- a692 1
-
- a693 2
- /* m->husband->xpos = xp; */
- /* m->wife->xpos = xp; */
- a694 1
-
- d719 1
- d754 1
- d768 2
- a769 2
- } while(moved && c < 10);
- if (c == 10)
- d850 2
- a851 1
- int l;
- d856 1
- a856 1
- l += strlen(pers->firstname);
- d862 16
- a877 2
-
- w = (opts->personfont.size * l) / 1.5;
- d1187 39
- @
-
-
- 1.2
- log
- @fixed layout problems of previous versions.
- @
- text
- @d7 1
- a7 1
- * $Date: 1994/02/17 23:50:21 $
- d11 1
- a11 1
- * $Revision: 1.1 $
- d16 3
- d31 1
- a31 1
- #define TREE_GAP 12
- d75 1
- d89 3
- d131 1
- a131 1
- adjust_layout(opts, opts->startperson);
- d289 5
- a293 2
- do_simple_layout(opts, child->id, child->xpos,
- child->ypos + opts->ticklen+1, level+1);
- d300 1
- a300 2
- /* marriage = nextmarriage(marriage, id); */
- marriage = NULL;
- d307 23
- d332 1
- a332 3
- int children;
- int ptwidth, startx, childy;
- person_t *child, *lastchild;
- d335 1
- a335 1
- dbprintf(( "\ndo_simple_layout: do layout part 2: ID: %lx, level %d\n", id, level));
- d356 1
- a356 2
- /* marriage = nextmarriage(marriage, id); */
- marriage = NULL;
- d386 1
- a386 2
- /* marriage = nextmarriage(marriage, id); */
- marriage = NULL;
- a388 1
-
- d392 23
- d423 12
- a434 4
- dbprintf(("set_left_links: marriage %s & %s level %d: child %s (lev: %d)\n",
- marriage->husband->firstname, marriage->wife->firstname,
- level, marriage->firstchild->firstname, marriage->firstchild->level));
- generation[level].first = marriage->firstchild;
- d440 3
- d454 2
- d459 23
- d490 12
- a501 4
- dbprintf(("set_right_links: marriage %s & %s level %d: child %s\n",
- marriage->husband->firstname, marriage->wife->firstname,
- level, marriage->firstchild->firstname));
- generation[level].last = marriage->lastchild;
- d507 3
- d521 2
- d546 2
- a547 2
- * the routine do_simple_layout and adjusts the positions
- * such that people do not overlap.
- d552 1
- a552 1
- void adjust_layout(options_t *opts, id_t id)
- d554 1
- a554 1
- int i, dx, moved;
- d559 1
- d575 6
- a580 1
- dx = (person->xpos - lastperson->xpos);
- d585 1
- a585 1
- lastperson->xpos, person->xpos, dx));
- d587 1
- a587 1
- if (dx < 0)
- d598 1
- d607 9
- a615 1
- dbprintf(("adjust_layout: moved child %s so moving parents %s & %s by %d\n",
- d617 1
- a617 1
- person->parents->wife->firstname, dx));
- d619 3
- a621 3
- person->parents->xpos += dx;
- person->parents->husband->xpos = person->parents->xpos;
- person->parents->wife->xpos = person->parents->xpos;
- d625 57
- d692 8
- a699 1
- } while(moved);
- a734 2
- person->xpos += dx;
-
- d747 3
- d841 1
- a841 1
- while(p = p->lastchild)
- d876 1
- a876 1
- dbprintf(("findleft_forw: look for marriage from %s / %s at level %d (backlink %s)\n",
- d978 1
- a978 1
- while(p = p->nextchild)
- d1073 25
- @
-
-
- 1.1
- log
- @Initial revision
- @
- text
- @d3 1
- a3 1
- * $RCSfile$
- d5 1
- a5 1
- * $Author$
- d7 1
- a7 1
- * $Date$
- d9 1
- a9 1
- * $State$
- d11 1
- a11 1
- * $Revision$
- d15 3
- a17 1
- * $Log$
- d19 1
- d30 7
- a36 1
- int people_moved;
- a71 2
- person_t *pers;
- marriage_t *marr;;
- d85 2
- d92 2
- d99 1
- d103 15
- a117 6
- do_simple_layout(opts, opts->startperson, (opts->pagewidth - opts->rmargin)/2, opts->title.linespc + 3*opts->person.linespc, 0);
- do
- {
- people_moved = FALSE;
- adjust_layout(opts, opts->startperson);
- } while(people_moved);
- d119 2
- d122 7
- d133 2
- d178 4
- a181 4
- int i, children;
- int ptwidth, startx, endx, childy;
- person_t *child;
- marriage_t *marriage, *m;
- d183 1
- a183 1
- dbprintf(( "\ndo_simple_layout: do layout for ID %s at: %d,%d\n", id, x,y));
- d185 1
- a185 1
- marriage = findmarriage(id);
- d198 1
- d202 13
- a214 2
- child->married = (findmarriage(child->id) != NULL);
- child->fullname = !streq(child->family, marriage->husband->family) || child->married;
- d216 8
- d225 1
- d227 1
- d247 2
- a248 2
- case H_CENTERED:
- startx = x - (ptwidth * 0.5);
- d251 1
- a251 1
- startx = x - (ptwidth * 0.33);
- d253 3
- a255 2
- case H_RIGHT:
- startx = x - (ptwidth * 0.67);
- d282 2
- a283 8
- if (level <= opts->maxlevel)
- {
- do_simple_layout(opts, child->id, child->xpos, child->ypos + opts->ticklen+1, level+1);
- }
- else
- {
- dbprintf(("do_simple_layout: marriage of %s %s skipped - too many levels.\n", child->firstname, child->family));
- }
- d289 15
- a303 1
- marriage = nextmarriage(marriage, id);
- d305 23
- a327 1
- x +=
- d330 33
- a362 1
- dbprintf(( "do_simple_layout: finished simple layout for ID %s.\n", id));
- d365 62
- d455 3
- a457 3
- person_t *child, *lastchild = NULL;
- marriage_t *m, *marriage;
- int newpos, dx;
- d459 2
- a460 4
- dbprintf(( "adjust_layout: examining tree for ID %s....\n", id));
-
- marriage = findmarriage(id);
- while(marriage)
- d462 2
- a463 2
- child = marriage->firstchild;
- while(child != NULL)
- d465 7
- a471 1
- if (child->married)
- d473 1
- a473 6
- adjust_layout(opts, child->id);
- m = findmarriage(child->id);
- }
- if (child->married && m->children > 0)
- {
- if (lastchild)
- d475 2
- a476 5
- newpos = m->firstchild->xpos;
- dx = lastchild->xpos - newpos;
- dbprintf(("adjust_layout: does child %s overlap %s (%d vs %d) ?",
- m->firstchild->firstname, lastchild->firstname,
- newpos, lastchild->xpos));
- d478 5
- a482 1
- if (dx > 0)
- d484 2
- a485 8
- person_t *c1;
-
- dbprintf((" ... yes\n"));
- people_moved = TRUE;
- dx += ((lastchild->width + m->firstchild->width) / 2 );
- dbprintf(("adjust_layout: dx += (%d + %d)/2 => %d\n",
- lastchild->width, m->firstchild->width, dx));
-
- d487 3
- a489 1
- * move the current & those right by dx
- d491 4
- a494 2
- c1 = child;
- while(c1)
- d496 2
- a497 13
- if (c1->married)
- {
- marriage_t *m1;
- m1 = findmarriage(c1->id);
- while(m1)
- {
- move_tree(m1, dx);
- m1 = nextmarriage(m1, c1->id);
- }
- }
- else
- c1->xpos += dx;
- c1 = c1->nextchild;
- d499 11
- a510 4
- else
- {
- dbprintf((" ... no\n"));
- }
- d512 3
- a514 1
- lastchild = m->lastchild;
- a515 1
- child = child->nextchild;
- d517 6
- a522 4
- marriage = nextmarriage(marriage, id);
- }
-
- dbprintf(( "adjust_layout: finished examining tree for ID %s...\n", id));
- d549 1
- a549 1
- void move_tree(marriage_t *marriage, int dx)
- d552 1
- a552 1
- marriage_t *m;
- d554 2
- a555 2
- dbprintf(( "move_tree: move marriage %s %s by %d\n",
- marriage->husband->firstname, marriage->wife->family, dx));
- d557 1
- a557 1
- marriage->xpos += dx;
- d559 1
- a559 1
- if (marriage->children > 0)
- d561 3
- d565 1
- a565 1
- while(child != NULL)
- d567 1
- a567 10
- child->xpos += dx;
-
- dbprintf(( "move_tree: move child %s %s by %d\n",
- child->firstname, child->family, dx));
-
- if (child->married)
- {
- m = findmarriage(child->id);
- move_tree(m, dx);
- }
- a575 92
- * Function:
- *
- *
- * Inputs:
- * outf - the output file to write PostScript to.
- * opts - current option set
- * id - the ID of the person to start at, who should be
- * married.
- *
- * Outputs:
- * (file)
- *
- * Error Handling:
- * None.
- *
- * Description:
- *
- *
- *
- *************************************************************
- )*/
-
- void print_tree(FILE *outf, options_t *opts, id_t id)
- {
- person_t *child;
- marriage_t *m, *marriage;
-
- marriage = findmarriage(id);
- while(marriage)
- {
- dbprintf(( "\nprint_tree: marriage at: %d,%d\n", marriage->xpos, marriage->ypos));
-
- /*
- * print this marriage.
- */
- printmarriage(outf, opts, marriage, marriage->xpos, marriage->ypos);
-
- if (marriage->children > 0)
- {
- int gap;
-
- dbprintf(( "print_tree: writing %d children ...\n", marriage->children));
-
- fprintf(outf, "1 setlinewidth\n");
-
- /*
- * gap allowed for the parents info.
- */
- gap = (opts->person.linespc * opts->marrlines) - (opts->ticklen);
-
- /*
- * draw a line 'connecting' the parents
- * to the children's line.
- */
- fprintf(outf, "%d %d moveto %d %d lineto stroke\n",
- XOF(opts, marriage->xpos), YOF(opts, marriage->ypos + gap),
- XOF(opts, marriage->xpos), YOF(opts, marriage->firstchild->ypos - opts->ticklen));
-
- /*
- * draw the horizontal line connecting
- * the children together.
- */
- fprintf(outf, "%d %d moveto %d 0 rlineto stroke\n",
- XOF(opts, marriage->firstchild->xpos), YOF(opts, marriage->firstchild->ypos - opts->ticklen),
- DXOF(opts, marriage->lastchild->xpos - marriage->firstchild->xpos));
-
- child = marriage->firstchild;
- while(child != NULL)
- {
- fprintf(outf, "%d %d moveto 0 %d rlineto stroke\n",
- XOF(opts, child->xpos), YOF(opts, child->ypos), DYOF(opts, -opts->ticklen));
-
- if (child->married)
- {
- print_tree(outf, opts, child->id);
- }
- else
- {
- printperson(outf, opts, child, child->xpos, child->ypos+opts->ticklen+1);
- }
- child = child->nextchild;
- }
- }
- marriage = nextmarriage(marriage, id);
- }
-
- dbprintf(( "print_tree: finished writing marriage.\n"));
- }
-
- /*(
- *************************************************************
- *
- a597 1
- person_t *child;
- d610 1
- a610 1
- w = (opts->person.size * l) / 1.5;
- d619 4
- a622 22
- /*(
- *************************************************************
- *
- * Function: printperson
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Error Handling:
- *
- *
- * Description:
- *
- * print an unmarried person centered at the position
- * (x,y)
- *
- *************************************************************
- )*/
- d624 1
- a624 1
- void printperson(FILE *outf, options_t *opts, person_t *person, int x, int y)
- d626 2
- a627 2
- char buf[64];
- int linepos;
- d629 5
- a633 4
- linepos = y;
- fprintf(outf, "%%\n%% print an unmarried person\n%%\n");
- fprintf(outf, "personfont setfont\n");
- if (opts->printids)
- d635 2
- a636 3
- linepos += opts->ident.linespc;
- fprintf(outf, "%d %d moveto (ID: %s) show\n",
- XOF(opts, x), YOF(opts, linepos), person->id);
- d638 1
- a638 8
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- if (person->fullname)
- fprintf(outf, "(%s %s) showcentered\n", person->firstname, person->family);
- else
- fprintf(outf, "(%s) showcentered\n", person->firstname);
- fprintf(outf, "datefont setfont\n");
- strcpy(buf, "(");
- if (person->born.known)
- d640 2
- a641 1
- strcat(buf, date2string(&person->born));
- d643 3
- a645 2
- strcat(buf, " - ");
- if (person->died.known)
- d647 39
- a685 1
- strcat(buf, date2string(&person->died));
- d687 2
- a688 3
- strcat(buf, ")");
- fprintf(outf, "%d %d moveto (%s) showcentered\n",
- XOF(opts, x), YOF(opts, y+opts->person.linespc), buf);
- a690 22
- /*(
- *************************************************************
- *
- * Function: printmarriage
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- * (file)
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * print two married people centered at the position
- * (x,y)
- *
- *************************************************************
- )*/
- d692 1
- a692 2
- void printmarriage(FILE *outf, options_t *opts, marriage_t *marriage,
- int x, int y)
- d694 2
- a695 3
- #if 0
- char buf[64];
- int linepos;
- d697 2
- a698 9
- linepos = y;
- fprintf(outf, "%%\n%% print a marriage\n%%\n");
- if (opts->printids)
- {
- fprintf(outf, "identfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(ID: %s) show\n", marriage->husband->id);
- linepos += opts->ident.linespc;
- }
- a699 22
- fprintf(outf, "personfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "( %s) show\n", marriage->husband->firstname);
- linepos += opts->person.linespc;
-
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "( %s) show\n", marriage->husband->family);
- linepos += opts->person.linespc;
- strcpy(buf, "(");
- if (marriage->husband->born.known)
- {
- strcat(buf, date2string(&marriage->husband->born));
- }
- strcat(buf, " - ");
- if (marriage->husband->died.known)
- {
- strcat(buf, date2string(&marriage->husband->died));
- }
- strcat(buf, ")");
- fprintf(outf, "datefont setfont\n");
- fprintf(outf, "%d %d moveto (%s) show\n", XOF(opts, x+1), YOF(opts, linepos), buf);
-
- d701 2
- a702 1
- * deal with the wife.
- d704 2
- a705 2
- linepos = y;
- if (opts->printids)
- d707 6
- a712 12
- fprintf(outf, "identfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(ID: %s) showright\n", marriage->wife->id);
- linepos += opts->ident.linespc;
- }
- fprintf(outf, "personfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(%s ) showright\n", marriage->wife->firstname);
- linepos += opts->person.linespc;
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(%s ) showright\n", marriage->wife->family);
- linepos += opts->person.linespc;
- d714 35
- a748 4
- strcpy(buf, "(");
- if (marriage->wife->born.known)
- {
- strcat(buf, date2string(&marriage->wife->born));
- a749 11
- strcat(buf, " - ");
- if (marriage->wife->died.known)
- {
- strcat(buf, date2string(&marriage->wife->died));
- }
- strcat(buf, ")");
- fprintf(outf, "datefont setfont\n");
- fprintf(outf, "%d %d moveto (%s) showright\n", XOF(opts, x-1), YOF(opts, linepos), buf);
- #else
- char buf[64];
- int linepos;
- d751 3
- a753 6
- linepos = y;
- fprintf(outf, "%%\n%% print a marriage\n%%\n");
- fprintf(outf, "personfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(%s %s) showcentered\n", marriage->husband->firstname, marriage->husband->family);
- linepos += opts->person.linespc;
- a754 7
- if (opts->printids)
- {
- fprintf(outf, "identfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(ID: %s) show\n", marriage->husband->id);
- linepos += opts->ident.linespc;
- }
- d756 4
- a759 14
- strcpy(buf, "(");
- if (marriage->husband->born.known)
- {
- strcat(buf, date2string(&marriage->husband->born));
- }
- strcat(buf, " - ");
- if (marriage->husband->died.known)
- {
- strcat(buf, date2string(&marriage->husband->died));
- }
- strcat(buf, ")");
- fprintf(outf, "datefont setfont\n");
- fprintf(outf, "%d %d moveto (%s) showcentered\n", XOF(opts, x), YOF(opts, linepos), buf);
- linepos += opts->person.linespc;
- d761 4
- a764 6
- /*
- * put an '=' between the people
- */
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(=) showcentered\n");
- linepos += opts->person.linespc;
- d766 3
- a768 7
- /*
- * deal with the wife.
- */
- fprintf(outf, "personfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(%s %s) showcentered\n", marriage->wife->firstname, marriage->wife->family);
- linepos += opts->person.linespc;
- d770 1
- a770 1
- if (opts->printids)
- d772 2
- a773 4
- fprintf(outf, "identfont setfont\n");
- fprintf(outf, "%d %d moveto\n", XOF(opts, x), YOF(opts, linepos));
- fprintf(outf, "(ID: %s) showcentered\n", marriage->wife->id);
- linepos += opts->ident.linespc;
- d775 1
- a775 3
-
- strcpy(buf, "(");
- if (marriage->wife->born.known)
- d777 2
- a778 1
- strcat(buf, date2string(&marriage->wife->born));
- d780 3
- a782 2
- strcat(buf, " - ");
- if (marriage->wife->died.known)
- d784 10
- a793 7
- strcat(buf, date2string(&marriage->wife->died));
- }
- strcat(buf, ")");
- fprintf(outf, "datefont setfont\n");
- fprintf(outf, "%d %d moveto (%s) showcentered\n", XOF(opts, x), YOF(opts, linepos), buf);
- #endif
- }
- d795 6
- a800 23
- /*(
- *************************************************************
- *
- * Function: do_title
- *
- *
- * Inputs:
- * outf - file to write PostScript to
- * opts - option settings, including the title etc.
- *
- * Outputs:
- * (file)
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * To print the title string of the tree. Optionally, to
- * place it in a grey box.
- *
- *************************************************************
- )*/
- d802 9
- a810 5
- void do_title(FILE *outf, options_t *opts)
- {
- int h;
- int lx, ty, rx, by;
- float ptsz = opts->title.size;
- d812 11
- a822 12
- fprintf(outf, "%%\n%% Draw the page title\n%%\n");
- if (opts->titlegreylevel < 1.0)
- {
- fprintf(outf, "%.3f setgray\n", opts->titlegreylevel);
- lx = 0;
- ty = 0;
- rx = opts->pagewidth - opts->rmargin;
- by = opts->title.size * 1.7;
- fprintf(outf, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto\n",
- XOF(opts, lx), YOF(opts, ty), XOF(opts, rx), YOF(opts, ty),
- XOF(opts, rx), YOF(opts, by), XOF(opts, lx), YOF(opts, by));
- fprintf(outf, "closepath gsave fill grestore 0 setgray stroke\n");
- a823 4
- fprintf(outf, "titlefont setfont\n");
- fprintf(outf, "%d %d moveto (%s) showcentered\n",
- XOF(opts, opts->pagewidth/2), YOF(opts, opts->title.linespc), opts->titlestr);
- }
- d825 1
- a825 62
- /*(
- *************************************************************
- *
- * Function: do_prolog
- *
- *
- * Inputs:
- * outf - the file to write to
- * opts - the current options set
- *
- * Outputs:
- * None.
- *
- * Error Handling:
- * None.
- *
- * Description:
- *
- * To output the appropriate DSC comments for the output
- * file and generate definitions of private procedures.
- *
- *************************************************************
- )*/
- void do_prolog(FILE *outf, options_t *opts)
- {
- time_t now;
-
- time(&now);
- fprintf(outf, "%%!PS-Adobe-3.0\n");
- fprintf(outf, "%%%%BoundingBox: (atend)\n");
- fprintf(outf, "%%%%CreatorTitle: Ftree version " VERSION " (" __DATE__ ")\n");
- fprintf(outf, "%%%%CreationDate: %s", ctime(&now));
- fprintf(outf, "%%%%DocumentSuppliedResources: font %s %s %s\n",
- opts->title.font, opts->ident.font, opts->person.font);
- fprintf(outf, "%%%%Pages: 1\n");
- fprintf(outf, "\n");
- fprintf(outf, "%%%%Page: 1 1\n");
- fprintf(outf, "%%%%BeginPageSetup\n");
- fprintf(outf, "10 dict begin\n");
- fprintf(outf, "systemdict /%s known { %s } if\n", opts->papertype, opts->papertype);
- fprintf(outf, "/showcentered { %% str showc -- \n");
- fprintf(outf, "dup stringwidth pop 2 div neg 0 rmoveto show\n");
- fprintf(outf, "} def\n");
- fprintf(outf, "/showright { %% str showc -- \n");
- fprintf(outf, "dup stringwidth pop neg 0 rmoveto show\n");
- fprintf(outf, "} def\n");
- fprintf(outf, "/fsf {findfont exch scalefont def} bind def\n");
- fprintf(outf, "/identfont %.1f /%s fsf\n", opts->ident.size, opts->ident.font);
- fprintf(outf, "/personfont %.1f /%s fsf\n", opts->person.size, opts->person.font);
- fprintf(outf, "/titlefont %.1f /%s fsf\n", opts->title.size, opts->title.font);
- fprintf(outf, "/datefont %.1f /%s fsf\n", opts->person.size-2, opts->person.font);
- if (opts->landscape)
- {
- fprintf(outf, "%%%%PageOrientation: Landscape\n");
- fprintf(outf, "gsave clippath pathbbox grestore\n");
- fprintf(outf, "4 dict begin /ury exch def /urx exch def /lly exch def /llx exch def\n");
- fprintf(outf, "-90 rotate urx neg lly neg translate\n");
- fprintf(outf, "end\n");
- }
- else
- fprintf(outf, "%%%%PageOrientation: Portrait\n");
- fprintf(outf, "%%%%EndPageSetup\n");
- a827 23
- /*(
- *************************************************************
- *
- * Function: do_epilog
- *
- *
- * Inputs:
- * outf - the file to write to
- * opts - the current options set
- *
- * Outputs:
- * none.
- *
- * Error Handling:
- * none.
- *
- * Description:
- *
- * To close off the postscript program with showpage and
- * appropriate DSC comments.
- *
- *************************************************************
- )*/
- d829 1
- a829 1
- void do_epilog(FILE *outf, options_t *opts)
- d831 2
- a832 8
- fprintf(outf, "showpage\n");
- fprintf(outf, "end %% of dict begin\n");
- fprintf(outf, "%%%%EndPage: 1 1\n");
- fprintf(outf, "%%%%Trailer:\n");
- fprintf(outf, "%%%%BoundingBox: %d %d %d %d\n",
- opts->bblx, opts->bbly, opts->bbux, opts->bbuy);
- fprintf(outf, "%%%%EOF\n");
- }
- d834 2
- a835 25
- /*(
- *************************************************************
- *
- * Function: date2string
- *
- *
- * Inputs:
- * d - pointer to a struct date
- *
- * Outputs:
- * char * - pointer to a statically allocated buffer
- *
- * Error Handling:
- * Copes with various forms of unknown date by placing
- * '?' characters in the returned string. Copes with 'd'
- * being NULL by returning "".
- *
- * Description:
- *
- * Formats a date into a string, accounting for the
- * values of some of the fields being unknown. The date format
- * is predefined and unchangeable.
- *
- *************************************************************
- )*/
- d837 1
- a837 15
- char *date2string(struct date *d)
- {
- static char buf[32];
- char tbuf[12];
-
- buf[0] = '\0';
- if (d == NULL)
- return;
-
- if (d->dvalid)
- sprintf(buf, "%d/", d->day);
- else
- strcpy(buf, "?/");
-
- if (d->mvalid)
- d839 2
- a840 2
- sprintf(tbuf, "%d/", d->month);
- strcat(buf, tbuf);
- d842 3
- a844 4
- else
- strcat(buf, "?/");
-
- if (d->yvalid)
- d846 6
- a851 5
- sprintf(tbuf, "%d", d->year);
- strcat(buf, tbuf);
- }
- else
- strcat(buf, "?");
- d853 20
- a872 3
- dbprintf(( "date2string: buf : %s\n", buf));
- return buf;
- }
- d874 14
- a887 33
-
- /*(
- *************************************************************
- *
- * Function: widthof
- *
- *
- * Inputs:
- *
- *
- * Outputs:
- *
- *
- * Error Handling:
- *
- *
- * Description:
- *
- * return the width required to print 'person'
- *
- *************************************************************
- )*/
-
- int widthof(options_t *opts, person_t *pers)
- {
- int w;
- person_t *child;
- int l;
-
- if (pers->fullname)
- {
- l = strlen(pers->family);
- l += strlen(pers->firstname);
- a888 4
- else
- {
- l = strlen(pers->firstname);
- }
- d890 2
- a891 6
- w = (opts->person.size * l) / 1.5;
- w = w + TREE_GAP;
-
- dbprintf(( "widthof: %s width of \"%s\" is \t%d (%dc).\n",
- (pers->fullname)?"full":"short", pers->firstname, w, l));
- return w;
- @
-