File o_box_basic.c
******************

File header
===========

     <<o_box_basic.c : *>>=
     <<o_box_basic.c : copyright and license -- o_box_basic.c - copyright and license>>

     /* DO NOT read or edit this file ! Use ../noweb/o_box_basic.nw instead */

     <<o_box_basic.c : include directives -- o_box_basic.c - include directives>>
     <<o_box_basic.c : macros -- o_box_basic.c - macros>>

     <<o_box_basic.c : o_box_add() -- o_box_basic.c - o_box_add()>>

     <<o_box_basic.c : o_box_copy() -- o_box_basic.c - o_box_copy()>>

     <<o_box_basic.c : o_box_modify() -- o_box_basic.c - o_box_modify()>>

     <<o_box_basic.c : o_box_read() -- o_box_basic.c - o_box_read()>>
     <<o_box_basic.c : o_box_save() -- o_box_basic.c - o_box_save()>>

     <<o_box_basic.c : o_box_translate() -- o_box_basic.c - o_box_translate()>>
     <<o_box_basic.c : o_box_translate_world() -- o_box_basic.c - o_box_translate_world()>>

     <<o_box_basic.c : o_box_rotate() -- o_box_basic.c - o_box_rotate()>>
     <<o_box_basic.c : o_box_rotate_world() -- o_box_basic.c - o_box_rotate_world()>>

     <<o_box_basic.c : o_box_mirror() -- o_box_basic.c - o_box_mirror()>>
     <<o_box_basic.c : o_box_mirror_world() -- o_box_basic.c - o_box_mirror_world()>>

     <<o_box_basic.c : o_box_recalc() -- o_box_basic.c - o_box_recalc()>>

     <<o_box_basic.c : get_box_bounds() -- o_box_basic.c - get_box_bounds()>>
     <<o_box_basic.c : world_get_box_bounds() -- o_box_basic.c - world_get_box_bounds()>>

     <<o_box_basic.c : o_box_print() -- o_box_basic.c - o_box_print()>>
     <<o_box_basic.c : o_box_print_solid() -- o_box_basic.c - o_box_print_solid()>>
     <<o_box_basic.c : o_box_print_dotted() -- o_box_basic.c - o_box_print_dotted()>>
     <<o_box_basic.c : o_box_print_dashed() -- o_box_basic.c - o_box_print_dashed()>>
     <<o_box_basic.c : o_box_print_center() -- o_box_basic.c - o_box_print_center()>>
     <<o_box_basic.c : o_box_print_phantom() -- o_box_basic.c - o_box_print_phantom()>>
     <<o_box_basic.c : o_box_print_filled() -- o_box_basic.c - o_box_print_filled()>>
     <<o_box_basic.c : o_box_print_mesh() -- o_box_basic.c - o_box_print_mesh()>>
     <<o_box_basic.c : o_box_print_hatch() -- o_box_basic.c - o_box_print_hatch()>>

     #if 0 /* original way of printing box, no longer used */
     <<o_box_basic.c : o_box_print_old() -- o_box_basic.c - o_box_print_old()>>
     #endif

     <<o_box_basic.c : o_box_image_write() -- o_box_basic.c - o_box_image_write()>>

     <<o_box_basic.c : copyright and license>>=
     /* gEDA - GPL Electronic Design Automation
      * libgeda - gEDA's library
      * Copyright (C) 1998-2000 Ales V. Hvezda
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
      * the Free Software Foundation; either version 2 of the License, or
      * (at your option) any later version.
      *
      * This program is distributed in the hope that it will be useful,
      * but WITHOUT ANY WARRANTY; without even the implied warranty of
      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      * GNU General Public License for more details.
      *
      * You should have received a copy of the GNU General Public License
      * along with this program; if not, write to the Free Software
      * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
      */

     <<o_box_basic.c : include directives>>=
     #include <config.h>
     #include <math.h>
     #include <stdio.h>

     #include <gtk/gtk.h>
     #include <libguile.h>

     #ifdef HAS_LIBGDGEDA
     #include <gdgeda/gd.h>
     #endif

     #include "defines.h"
     #include "struct.h"
     #include "globals.h"
     #include "o_types.h"
     #include "colors.h"
     #include "funcs.h"

     #include "../include/prototype.h"

     #ifdef HAVE_LIBDMALLOC
     #include <dmalloc.h>
     #endif

     <<o_box_basic.c : macros>>=
     /* Kazu on July 16, 1999 - Added these macros to simplify the code */
     #define GET_BOX_WIDTH(w)                        \
             abs((w)->last_x - (w)->start_x)
     #define GET_BOX_HEIGHT(w)                       \
                     abs((w)->last_y - (w)->start_y)
     #define GET_BOX_LEFT(w)                         \
                     min((w)->start_x, (w)->last_x);
     #define GET_BOX_TOP(w)                          \
                     min((w)->start_y, (w)->last_y);

          Defines :
          .
          .
          .
          .

     }

Function o_box_add()
====================

 -- Function: o_box_add w_current object_list type color x1 y1 x2 y2
     This function creates a new object representing a box. This object is added to the end of the list object_list pointed object belongs to. The box is described by its upper left corner - x1, y1 - and its lower right corner - x2, y2. The type parameter must be equal to OBJ_BOX. The color corresponds to the color the box will be drawn with.

The OBJECT structure is allocated with the s_basic_init_object() function. The structure describing the box is allocated and initialized with the parameters given to the function.

Both the line type and the filling type are set to default values : solid line type with a width of 0, and no filling. It can be changed after with the o_set_line_options() and o_set_fill_options().

The object is added to the end of the list described by the object_list parameter by the s_basic_link_object().

The function returns a new pointer on the end of the object list.

     <<o_box_basic.c : o_box_add()>>=
     OBJECT *
     o_box_add(TOPLEVEL *w_current, OBJECT *object_list,
                       char type, int color,
                       int x1, int y1, int x2, int y2)
     {
       OBJECT *new_node;
       BOX *box;

       <<o_box_add() : allocate memory for the new box -- o_box_add() - allocate memory for the new box>>

       <<o_box_add() : initialize the box -- o_box_add() - initialize the box>>

       <<o_box_add() : calculate the screen coords and the bounding box -- o_box_add() - calculate the screen coords and the bounding box>>

       <<o_box_add() : add the object to the list -- o_box_add() - add the object to the list>>

       return(object_list);
     }

          Defines :
          o_box_add,
           -- o_box_copy() - create and insert a new object in the list,
           -- o_box_read() - add the new box to the list of objects.

     }

     <<o_box_add() : allocate memory for the new box>>=
     /* create the object */
     new_node        = s_basic_init_object("box");
     new_node->type  = type;
     new_node->color = color;

     box = (BOX *) malloc(sizeof(BOX));
     new_node->box   = box;

     <<o_box_add() : initialize the box>>=
     /* describe the box with its upper left and lower right corner */
     box->upper_x = x1;
     box->upper_y = y1;
     box->lower_x = x2;
     box->lower_y = y2;

     /* line type and filling initialized to default */
     o_set_line_options(w_current, new_node,
                                        END_NONE, TYPE_SOLID, 0, -1, -1);
     o_set_fill_options(w_current, new_node,
                                        FILLING_HOLLOW, -1, -1, -1, -1, -1);

     /* TODO: questionable cast */
     new_node->draw_func = (void *) box_draw_func;
     /* TODO: questionable cast */
     new_node->sel_func  = (void *) select_func;

     <<o_box_add() : calculate the screen coords and the bounding box>>=
     /* compute the bounding box */
     o_box_recalc(w_current, new_node);

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

     <<o_box_add() : add the object to the list>>=
     /* add the object to the list */
     object_list = (OBJECT *) s_basic_link_object(new_node, object_list);

Function o_box_copy()
=====================

 -- Function: o_box_copy w_current list_tail o_current
     The function o_box_copy() creates a verbatim copy of the object pointed by o_current describing a box. The new object is added at the end of the list, following the list_tail pointed object.

The function returns a new pointer on the end of the object list.

     <<o_box_basic.c : o_box_copy()>>=
     OBJECT *
     o_box_copy(TOPLEVEL *w_current, OBJECT *list_tail, OBJECT *o_current)
     {
       OBJECT *new_obj;
       ATTRIB *a_current;
       int color;

       if (o_current->saved_color == -1) {
         color = o_current->color;
       } else {
         color = o_current->saved_color;
       }

       <<o_box_copy() : create and insert a new object in the list -- o_box_copy() - create and insert a new object in the list>>

       <<o_box_copy() : modify the fields of the new object -- o_box_copy() - modify the fields of the new object>>

       <<o_box_copy() : copy the attributes -- o_box_copy() - copy the attributes>>

       /* return the new tail of the object list */
       return(new_obj);
     }

          Defines :
          .

     }

A new box object is added at the end of the object list with o_box_add(). Values for its fields are default and need to be modified.

     <<o_box_copy() : create and insert a new object in the list>>=
     /* create and link a new box object */
     new_obj = o_box_add(w_current, list_tail,
                                             OBJ_BOX, color,
                                             0, 0, 0, 0);

          Uses :
          o_box_add,  -- o_box_basic.c - o_box_add().

     }

The dimensions of the new box are set with the ones of the original box. The two boxes have the same line type and the same filling options.

The coordinates and the values in screen unit are computed with o_box_recalc().

     <<o_box_copy() : modify the fields of the new object>>=
     /* modifying */
     /* pb20011002 - have to check if o_current is a box object */
     new_obj->box->upper_x = o_current->box->upper_x;
     new_obj->box->upper_y = o_current->box->upper_y;
     new_obj->box->lower_x = o_current->box->lower_x;
     new_obj->box->lower_y = o_current->box->lower_y;

     o_set_line_options(w_current, new_obj, o_current->line_end,
                                        o_current->line_type, o_current->line_width,
                                        o_current->line_length, o_current->line_space);
     o_set_fill_options(w_current, new_obj,
                                        o_current->fill_type, o_current->fill_width,
                                        o_current->fill_pitch1, o_current->fill_angle1,
                                        o_current->fill_pitch2, o_current->fill_angle2);

     o_box_recalc(w_current, new_obj);

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

     <<o_box_copy() : copy the attributes>>=
     /*      new_obj->attribute = 0;*/
     a_current = o_current->attribs;
     if (a_current) {
         while ( a_current ) {

                     /* head attrib node has prev = NULL */
                     if (a_current->prev != NULL) {
                             a_current->copied_to = new_obj;
                     }
                     a_current = a_current->next;
         }
     }

Function o_box_modify()
=======================

 -- Function: o_box_modify w_current object x y whichone
     This function modifies the coordinates of one of the four corner of the box. The new coordinates of the corner identified by whichone are given by x and y in world unit.

The coordinates of the corner is modified in the world coordinate system. Screen coordinates and boundings are then updated.

     <<o_box_basic.c : o_box_modify()>>=
     /* pb20011002 - rewritten : old one did not used x, y and whichone */
     void
     o_box_modify(TOPLEVEL *w_current, OBJECT *object,
                              int x, int y, int whichone)
     {
             int tmp;

             /* change the position of the selected corner */
             switch(whichone) {
                     case BOX_UPPER_LEFT:
                             object->box->upper_x = x;
                             object->box->upper_y = y;
                             break;

                     case BOX_LOWER_LEFT:
                             object->box->upper_x = x;
                             object->box->lower_y = y;
                             break;

                     case BOX_UPPER_RIGHT:
                             object->box->lower_x = x;
                             object->box->upper_y = y;
                             break;

                     case BOX_LOWER_RIGHT:
                             object->box->lower_x = x;
                             object->box->lower_y = y;
                             break;

                     default:
                             return;
             }

             /* need to update the upper left and lower right corners */
             if(object->box->upper_x > object->box->lower_x) {
                     tmp                  = object->box->upper_x;
                     object->box->upper_x = object->box->lower_x;
                     object->box->lower_x = tmp;
             }

             if(object->box->upper_y < object->box->lower_y) {
                     tmp                  = object->box->upper_y;
                     object->box->upper_y = object->box->lower_y;
                     object->box->lower_y = tmp;
             }

             /* recalculate the screen coords and the boundings */
             o_box_recalc(w_current, object);

     }

          Defines :
          .

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

Function o_box_read()
=====================

 -- Function: o_box_read w_current object_list buf version
     The function o_box_read() get from the character string *buf the description of a box. The new box is then added to the list of object of which *object_list is the last element before the call. The function returns the new last element, that is the added box object.

Depending on *version, the correct file format is considered. Currently two file format revisions are supported :

  * the file format used until 20000704 release ;

  * the file format used for the releases after 2000704.

     <<o_box_basic.c : o_box_read()>>=
     OBJECT *
     o_box_read(TOPLEVEL *w_current, OBJECT *object_list, char buf[],
                unsigned int release_ver, unsigned int fileformat_ver)
     {
             char type;
             int x1, y1;
             int width, height;
             int d_x1, d_y1;
             int d_x2, d_y2;
             int color;
             int box_width, box_space, box_length;
             int fill_width, angle1, pitch1, angle2, pitch2;
             int box_end;
             int box_type;
             int box_filling;

             if(release_ver <= VERSION_20000704) {
                     <<o_box_read() : old geda file format -- o_box_read() - old geda file format>>

             } else {
                     <<o_box_read() : geda file format after release 20000704 -- o_box_read() - geda file format after release 20000704>>

             }

             <<o_box_read() : check the values of the parameters -- o_box_read() - check the values of the parameters>>

             <<o_box_read() : add the new box to the list of objects -- o_box_read() - add the new box to the list of objects>>

             return(object_list);
     }

          Defines :
          .

     }

The old geda file format, i.e. releases 20000704 and older, does not handle the line type and the filling of the box object. They are set to default.

     <<o_box_read() : old geda file format>>=
     sscanf(buf, "%c %d %d %d %d %d\n",
                &type, &x1, &y1, &width, &height, &color);

     box_width   = 0;
     box_end     = END_NONE;
     box_type    = TYPE_SOLID;
     box_length  = -1;
     box_space   = -1;

     box_filling = FILLING_HOLLOW;
     fill_width  = 0;
     angle1      = -1;
     pitch1      = -1;
     angle2      = -1;
     pitch2      = -1;

The current line format to describe a box is a space separated list of characters and numbers in plain ASCII on a single line. The meaning of each item is described in the file format documentation.

     <<o_box_read() : geda file format after release 20000704>>=
     sscanf(buf, "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
                &type, &x1, &y1, &width, &height, &color,
                &box_width, &box_end, &box_type, &box_length,
                &box_space, &box_filling,
                &fill_width, &angle1, &pitch1, &angle2, &pitch2);

     <<o_box_read() : check the values of the parameters>>=
     if (width == 0 || height == 0) {
         fprintf(stderr, "Found a zero width/height box [ %c %d %d %d %d %d ]\n",
                 type, x1, y1, width, height, color);
         s_log_message("Found a zero width/height box [ %c %d %d %d %d %d ]\n",
                       type, x1, y1, width, height, color);
     }

     if (color < 0 || color > MAX_COLORS) {
         fprintf(stderr, "Found an invalid color [ %s ]\n", buf);
         s_log_message("Found an invalid color [ %s ]\n", buf);
         s_log_message("Setting color to WHITE\n");
         color = WHITE;
     }

A box is internally described by its lower right and upper left corner whereas the line describe it with the lower left corner and the width and height.

A new object is allocated, initialized and added to the object list. Its filling and line type are set according to the values of the field on the line.

     <<o_box_read() : add the new box to the list of objects>>=
     /* upper left corner of the box */
     d_x1 = x1;
     d_y1 = y1+height; /* move box origin to top left */

     /* lower right corner of the box */
     d_x2 = x1+width; /* end points of the box */
     d_y2 = y1;

     /* create and add the box to the list */
     object_list = (OBJECT *) o_box_add(w_current, object_list,
                                                                        type, color,
                                                                        d_x1, d_y1, d_x2, d_y2);
     /* set its line options */
     o_set_line_options(w_current, object_list,
                                        box_end, box_type, box_width,
                                        box_length, box_space);
     /* set its fill options */
     o_set_fill_options(w_current, object_list,
                                        box_filling, fill_width,
                                        pitch1, angle1, pitch2, angle2);

          Uses :
          o_box_add,  -- o_box_basic.c - o_box_add().

     }

Function o_box_save()
=====================

 -- Function: o_box_save buf object
     This function formats a string in the buffer *buff to describe the box object *object. It follows the post-20000704 release file format that handle the line type and fill options. A pointer to the new allocated and formated string is returned. The string must be freed at some point.

     <<o_box_basic.c : o_box_save()>>=
     char *
     o_box_save(OBJECT *object)
     {
       int x1, y1;
       int width, height;
       int color;
       int box_width, box_space, box_length;
       int fill_width, angle1, pitch1, angle2, pitch2;
       OBJECT_END box_end;
       OBJECT_TYPE box_type;
       OBJECT_FILLING box_fill;
       char *buf;

       <<o_box_save() : prepare the description of the box -- o_box_save() - prepare the description of the box>>

       <<o_box_save() : describe a box with post-20000704 file format -- o_box_save() - describe a box with post-20000704 file format>>

       return(buf);
     }

          Defines :
          .

     }

A box is internally represented by its lower right and upper left corner whereas it is described in the file format as its lower left corner and its width and height.

     <<o_box_save() : prepare the description of the box>>=
     /* calculate the width and height of the box */
     width  = abs(object->box->lower_x - object->box->upper_x);
     height = abs(object->box->upper_y - object->box->lower_y);

     /* calculate the lower left corner of the box */
     x1 = object->box->upper_x;
     y1 = object->box->upper_y - height; /* move the origin to 0, 0*/

     #if DEBUG
     printf("box: %d %d %d %d\n", x1, y1, width, height);
     #endif

     /* description of the line type for the outline */
     box_end    = object->line_end;
     box_width  = object->line_width;
     box_type   = object->line_type;
     box_length = object->line_length;
     box_space  = object->line_space;

     /* description of the filling of the box */
     box_fill   = object->fill_type;
     fill_width = object->fill_width;
     angle1     = object->fill_angle1;
     pitch1     = object->fill_pitch1;
     angle2     = object->fill_angle2;
     pitch2     = object->fill_pitch2;

     /* Use the right color */
     if (object->saved_color == -1) {
         color = object->color;
     } else {
         color = object->saved_color;
     }

     <<o_box_save() : describe a box with post-20000704 file format>>=
     buf = g_strdup_printf("%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                           object->type,
                           x1, y1, width, height, color,
                           box_width, box_end, box_type, box_length, box_space,
                           box_fill,
                           fill_width, angle1, pitch1, angle2, pitch2);

Function o_box_translate()
==========================

 -- Function: o_box_translate w_current dx dy object
     This function applies a translation of (dx,dy) to the box described by *object. dx and dy are in screen unit.

The translation vector is converted in world unit. The translation is made with o_box_translate_world().

     <<o_box_basic.c : o_box_translate()>>=
     void
     o_box_translate(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
     {
       int world_dx, world_dy;

       if (object == NULL) printf("bt NO!\n");

       /* convert the translation vector in world unit */
       world_dx = SCREENabs(w_current, dx);
       world_dy = SCREENabs(w_current, dy);

       /* translate the box */
       o_box_translate_world(w_current, world_dx, world_dy, object);

       /* screen coords and boundings are updated by _translate_world */

     }

          Defines :
          .

          Uses :
          o_box_translate_world,  -- o_box_basic.c - o_box_translate_world().

     }

Function o_box_translate_world()
================================

 -- Function: o_box_translate_world w_current x1 y1 object
     This function applies a translation of (x1,y1) to the box described by *object. x1 and y1 are in world unit.

     <<o_box_basic.c : o_box_translate_world()>>=
     void
     o_box_translate_world(TOPLEVEL *w_current, int x1, int y1, OBJECT *object)
     {
       if (object == NULL) printf("btw NO!\n");

       <<o_box_translate_world() : translate the box -- o_box_translate_world() - translate the box>>

       <<o_box_translate_world() : update the screen coordinates -- o_box_translate_world() - update the screen coordinates>>

     }

          Defines :
          o_box_translate_world,
           -- o_box_basic.c - o_box_translate().

     }

     <<o_box_translate_world() : translate the box>>=
     /* Do world coords */
     object->box->upper_x = object->box->upper_x + x1;
     object->box->upper_y = object->box->upper_y + y1;
     object->box->lower_x = object->box->lower_x + x1;
     object->box->lower_y = object->box->lower_y + y1;

     <<o_box_translate_world() : update the screen coordinates>>=
     /* recalc the screen coords and the bounding box */
     o_box_recalc(w_current, object);

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

Function o_box_rotate()
=======================

 -- Function: o_box_rotate w_current centerx centery angle object
     This function applies a rotation of center (centerx, centery) and angle angle to the box object *object. The coordinates of the rotation center are in screen units. angle must be a 90 degree multiple. If not, no rotation is applied.

The rotation is made with the o_box_rotate_world() function that perform a rotation of angle angle and center (world_centerx, world_centery) in world unit.

     <<o_box_basic.c : o_box_rotate()>>=
     /* takes in screen coordinates for the centerx,y, and then does the rotate
      * in world space */
     /* also ignores angle argument... for now, rotate only in 90 degree
      * increments */
     /* fixed to 90 degrees... it's *not* general now */
     void
     o_box_rotate(TOPLEVEL *w_current,
                              int centerx, int centery, int angle,
                  OBJECT *object)
     {
       int world_centerx, world_centery;

       /* convert the center of rotation to world unit */
       SCREENtoWORLD(w_current,
                                     centerx, centery,
                     &world_centerx, &world_centery);

       /* rotate the box */
       /* the check of the rotation angle is in o_box_rotate_world() */
       o_box_rotate_world(w_current,
                                              world_centerx, world_centery, angle,
                                              object);

       /* screen coords and boundings are updated by _rotate_world() */

     }

          Defines :
          .

          Uses :
          o_box_rotate_world,  -- o_box_basic.c - o_box_rotate_world().

     }

Function o_box_rotate_world()
=============================

 -- Function: o_box_rotate_world w_current world_centerx world_centery angle object
     The function o_box_rotate_world() rotate the box described by *object around the (world_centerx, world_centery) point by angle degrees. The center of rotation is in world unit.

     <<o_box_basic.c : o_box_rotate_world()>>=
     void
     o_box_rotate_world(TOPLEVEL *w_current,
                        int world_centerx, int world_centery, int angle,
                        OBJECT *object)
     {
             int newx1, newy1;
             int newx2, newy2;

             <<o_box_rotate_world() : check the rotation angle -- o_box_rotate_world() - check the rotation angle>>

             <<o_box_rotate_world() : rotate the box world coords -- o_box_rotate_world() - rotate the box world coords>>

             <<o_box_rotate_world() : update the screen coords -- o_box_rotate_world() - update the screen coords>>

     }

          Defines :
          o_box_rotate_world,
           -- o_box_basic.c - o_box_rotate().

     }

Only 90 degree multiple and positive angles are allowed.

     <<o_box_rotate_world() : check the rotation angle>>=
     /* angle must be positive */
     if(angle < 0) angle = -angle;
     /* angle must be a 90 multiple or no rotation performed */
     if((angle % 90) != 0) return;

The center of rotation (world_centerx, world_centery) is translated to the origin. The rotation of the upper left and lower right corner are then performed. Finally, the rotated box is translated back to its previous location.

     <<o_box_rotate_world() : rotate the box world coords>>=
     /* translate object to origin */
     object->box->upper_x -= world_centerx;
     object->box->upper_y -= world_centery;
     object->box->lower_x -= world_centerx;
     object->box->lower_y -= world_centery;

     /* rotate the upper left corner of the box */
     rotate_point_90(object->box->upper_x, object->box->upper_y, angle,
                                     &newx1, &newy1);

     /* rotate the lower left corner of the box */
     rotate_point_90(object->box->lower_x, object->box->lower_y, angle,
                                     &newx2, &newy2);

     /* reorder the corners after rotation */
     object->box->upper_x = min(newx1,newx2);
     object->box->upper_y = max(newy1,newy2);
     object->box->lower_x = max(newx1,newx2);
     object->box->lower_y = min(newy1,newy2);

     /* translate object back to normal position */
     object->box->upper_x += world_centerx;
     object->box->upper_y += world_centery;
     object->box->lower_x += world_centerx;
     object->box->lower_y += world_centery;

     <<o_box_rotate_world() : update the screen coords>>=
     /* recalc boundings and screen coords */
     o_box_recalc(w_current, object);

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

Function o_box_mirror()
=======================

 -- Function: o_box_mirror w_current centerx centery object
     This function mirrors the box from the point (centerx,centery) in screen unit.

The origin of the mirror in screen unit is converted in world unit. The box is mirrored with the function o_box_mirror_world() for which the origin of the mirror must be given in world unit.

     <<o_box_basic.c : o_box_mirror()>>=
     void
     o_box_mirror(TOPLEVEL *w_current,
                              int centerx, int centery,
                              OBJECT *object)
     {
       int world_centerx, world_centery;

       /* convert the origin of mirror */
       SCREENtoWORLD(w_current, centerx, centery,
                     &world_centerx,
                     &world_centery);

       /* apply the mirror in world coords */
       o_box_mirror_world(w_current,
                                              world_centerx, world_centery,
                                              object);

       /* screen coords and boundings are updated by _mirror_world() */

     }

          Defines :
          .

          Uses :
          o_box_mirror_world,  -- o_box_basic.c - o_box_mirror_world().

     }

Function o_box_mirror_world()
=============================

 -- Function: o_box_mirror_world w_current world_centerx world_centery object
     This function mirrors the box from the point (world_centerx,world_centery) in world unit.

The box is first translated to the origin, then mirrored and finally translated back at its previous position.

     <<o_box_basic.c : o_box_mirror_world()>>=
     void
     o_box_mirror_world(TOPLEVEL *w_current,
                                        int world_centerx, int world_centery,
                        OBJECT *object)
     {
       int newx1, newy1;
       int newx2, newy2;

       /* translate object to origin */
       object->box->upper_x -= world_centerx;
       object->box->upper_y -= world_centery;
       object->box->lower_x -= world_centerx;
       object->box->lower_y -= world_centery;

       /* mirror the corners */
       newx1 = -object->box->upper_x;
       newy1 = object->box->upper_y;
       newx2 = -object->box->lower_x;
       newy2 = object->box->lower_y;

       /* reorder the corners */
       object->box->upper_x = min(newx1,newx2);
       object->box->upper_y = max(newy1,newy2);
       object->box->lower_x = max(newx1,newx2);
       object->box->lower_y = min(newy1,newy2);

       /* translate back in position */
       object->box->upper_x += world_centerx;
       object->box->upper_y += world_centery;
       object->box->lower_x += world_centerx;
       object->box->lower_y += world_centery;

       /* recalc boundings and screen coords */
       o_box_recalc(w_current, object);

     }

          Defines :
          o_box_mirror_world,
           -- o_box_basic.c - o_box_mirror().

          Uses :
          o_box_recalc,  -- o_box_basic.c - o_box_recalc().

     }

Function o_box_recalc()
=======================

 -- Function: o_box_recalc w_current o_current
     This function recalculates the screen coords of the o_current pointed box object from its world coords.

The box coordinates and its bounding are recalculated as well as the OBJECT specific fields (line width, filling ...).

     <<o_box_basic.c : o_box_recalc()>>=
     void
     o_box_recalc(TOPLEVEL *w_current, OBJECT *o_current)
     {
       int left, top, right, bottom;
       int screen_x1, screen_y1;
       int screen_x2, screen_y2;

       if (o_current->box == NULL) {
         return;
       }

       <<o_box_recalc() : update the screen coords from world coords -- o_box_recalc() - update the screen coords from world coords>>

       <<o_box_recalc() : update the bounding box in screen unit -- o_box_recalc() - update the bounding box in screen unit>>

       <<o_box_recalc() : update the object general fields -- o_box_recalc() - update the object general fields>>

     }

          Defines :
          o_box_recalc,
           -- o_box_basic.c - o_box_mirror_world(),
           -- o_box_copy() - modify the fields of the new object,
           -- o_box_translate_world() - update the screen coordinates,
           -- o_box_rotate_world() - update the screen coords,
           -- o_box_add() - calculate the screen coords and the bounding box,
           -- o_box_basic.c - o_box_modify().

     }

     <<o_box_recalc() : update the screen coords from world coords>>=
     /* update the screen coords of the upper left corner of the box */
     WORLDtoSCREEN(w_current,
                               o_current->box->upper_x, o_current->box->upper_y,
                               &screen_x1, &screen_y1);
     o_current->box->screen_upper_x = screen_x1;
     o_current->box->screen_upper_y = screen_y1;

     /* update the screen coords of the lower right corner of the box */
     WORLDtoSCREEN(w_current,
                               o_current->box->lower_x, o_current->box->lower_y,
                               &screen_x2, &screen_y2);
     o_current->box->screen_lower_x = screen_x2;
     o_current->box->screen_lower_y = screen_y2;

     <<o_box_recalc() : update the bounding box in screen unit>>=
     /* update the bounding box - screen unit */
     get_box_bounds(w_current, o_current->box, &left, &top, &right, &bottom);
     o_current->left   = left;
     o_current->top    = top;
     o_current->right  = right;
     o_current->bottom = bottom;

          Uses :
          get_box_bounds,  -- o_box_basic.c - get_box_bounds().

     }

     <<o_box_recalc() : update the object general fields>>=
     /* recalc OBJECT specific parameters */
     o_object_recalc(w_current, o_current);

Function get_box_bounds()
=========================

 -- Function: get_box_bounds w_current object left top right bottom
     The get_box_bounds() function set the left, top, right and bottom pointed variables to the boundings of the box object described in *box in screen unit.

     <<o_box_basic.c : get_box_bounds()>>=
     void
     get_box_bounds(TOPLEVEL *w_current, BOX *box,
                                int *left, int *top, int *right, int *bottom)
     {
       *left   = box->screen_upper_x;
       *top    = box->screen_upper_y;
       *right  = box->screen_lower_x;
       *bottom = box->screen_lower_y;

       /* PB : bounding box has to take into account the width of the line */
       /* PB : but line width is unknown here */

       *left   = *left   - 4;
       *top    = *top    - 4;
       *right  = *right  + 4;
       *bottom = *bottom + 4;
     }

          Defines :
          get_box_bounds,
           -- o_box_recalc() - update the bounding box in screen unit.

     }

Function world_get_box_bounds()
===============================

 -- Function: world_get_box_bounds w_current box left top right bottom
     The world_get_box_bounds() function sets the left, top, right and bottom pointed variables to the boundings of the box object described in *box in world unit.

     <<o_box_basic.c : world_get_box_bounds()>>=
     void
     world_get_box_bounds(TOPLEVEL *w_current, BOX *box,
                                              int *left, int *top, int *right, int *bottom)
     {
             /* pb20011002 - why using min and max here and not above ? */
             *left   = min(box->upper_x, box->lower_x);
             *top    = min(box->upper_y, box->lower_y);
             *right  = max(box->upper_x, box->lower_x);
             *bottom = max(box->upper_y, box->lower_y);

             /* PB : same as above here for width of edges */

     #if DEBUG
             printf("box: %d %d %d %d\n", *left, *top, *right, *bottom);
     #endif

     }

          Defines :
          .

     }

Function o_box_print()
======================

 -- Function: o_box_print w_current fp o_current origin_x origin_y
     This function write in a postscript file the box described by the o_current pointed object. It takes into account its line type and fill type. The postscript resulting file is descibed by the file pointer fp.

The validity of the o_current pointer is verified : a null pointer causes an error message and a return.

The description of the box is extracted from the o_current pointed object : the coordinates of the box - upper left corner and width and height of the box -, its line type, its fill type.

The outline and the inside of the box are successively handled by two differend sets of functions.

     <<o_box_basic.c : o_box_print()>>=
     void
     o_box_print(TOPLEVEL *w_current, FILE *fp, OBJECT *o_current,
                              int origin_x, int origin_y)
     {
       int x, y, width, height;
       int color;
       int line_width, length, space;
       int fill_width, angle1, pitch1, angle2, pitch2;
       void (*outl_func)() = NULL;
       void (*fill_func)() = NULL;

       if (o_current == NULL) {
         printf("got null in o_box_print\n");
         return;
       }

       x = o_current->box->upper_x;
       y = o_current->box->upper_y;
       width  = abs(o_current->box->lower_x - o_current->box->upper_x);
       height = abs(o_current->box->lower_y - o_current->box->upper_y);
       color  = o_current->color;

       <<o_box_print() : printing outline -- o_box_print() - printing outline>>
       <<o_box_print() : printing the filling -- o_box_print() - printing the filling>>

     }

          Defines :
          o_box_print,
           -- o_box_basic.c - o_box_print_old().

     }

Depending on the type of the line for this particular box, the appropriate function is chosen among o_box_print_solid(), o_box_print_dotted(), o_box_print_dashed(), o_box_print_center and o_box_print_phantom().

The needed parameters for each of these type is extracted from the o_current object. Depending on the type, unused parameters are set to -1.

In the eventuality of a length and/or space null, the line is printed solid to avoid and endless loop produced by other functions in such a case.

     <<o_box_print() : printing outline>>=
     line_width = o_current->line_width;
     length = o_current->line_length;
     space  = o_current->line_space;

     switch(o_current->line_type) {
         case(TYPE_SOLID):
                     length = -1; space  = -1;
                     outl_func = (void *) o_box_print_solid;
                     break;

         case(TYPE_DOTTED):
                     length = -1;
                     outl_func = (void *) o_box_print_dotted;
                     break;

         case(TYPE_DASHED):
                     outl_func = (void *) o_box_print_dashed;
                     break;

         case(TYPE_CENTER):
                     outl_func = (void *) o_box_print_center;
                     break;

         case(TYPE_PHANTOM):
                     outl_func = (void *) o_box_print_phantom;
                     break;

         case(TYPE_ERASE):
                             /* Unused for now, print it solid */
                     length = -1; space  = -1;
                     outl_func = (void *) o_box_print_solid;
                     break;
     }

     if((length == 0) || (space == 0)) {
         length = -1; space  = -1;
         outl_func = (void *) o_box_print_solid;
     }

     (*outl_func)(w_current, fp,
                              x, y, width, height,
                              color,
                              line_width,
                              length, space,
                              origin_x, origin_y);

          Uses :
          o_box_print_center,  -- o_box_basic.c - o_box_print_center().
          o_box_print_dashed,  -- o_box_basic.c - o_box_print_dashed().
          o_box_print_dotted,  -- o_box_basic.c - o_box_print_dotted().
          o_box_print_phantom,  -- o_box_basic.c - o_box_print_phantom().
          o_box_print_solid,  -- o_box_basic.c - o_box_print_solid().

     }

If the filling type of the box is not HOLLOW, the appropriate function is chosen among o_box_print_filled(), o_box_print_mesh() and o_box_print_hatch(). The corresponding parameters are extracted from the o_current object and corrected afterward.

The case where pitch1 and pitch2 are null or negative is avoided as it leads to an endless loop in most of the called functions. In such a case, the box is printed filled. Unused parameters for each of these functions are set to -1 or any passive value.

     <<o_box_print() : printing the filling>>=
     if(o_current->fill_type != FILLING_HOLLOW) {
         fill_width = o_current->fill_width;
         angle1     = o_current->fill_angle1;
         pitch1     = o_current->fill_pitch1;
         angle2     = o_current->fill_angle2;
         pitch2     = o_current->fill_pitch2;

         switch(o_current->fill_type) {
                     case(FILLING_FILL):
                             angle1 = -1; pitch1 = 1;
                             angle2 = -1; pitch2 = 1;
                             fill_width = -1;
                             fill_func = (void *) o_box_print_filled;
                             break;

                     case(FILLING_MESH):
                             fill_func = (void *) o_box_print_mesh;
                             break;

                     case(FILLING_HATCH):
                             angle2 = -1; pitch2 = 1;
                             fill_func = (void *) o_box_print_hatch;
                             break;

                     case(FILLING_VOID):
                                     /* Unused for now, print it filled */
                             angle1 = -1; pitch1 = 1;
                             angle2 = -1; pitch2 = 1;
                             fill_width = -1;
                             fill_func = (void *) o_box_print_filled;
                             break;
                     case(FILLING_HOLLOW):
                       /* nop */
                       break;

         }

         if((pitch1 <= 0) || (pitch2 <= 0)) {
                     angle1 = -1; pitch1 = 1;
                     angle2 = -1; pitch2 = 1;
                     fill_func = (void *) o_box_print_filled;
         }

         (*fill_func)(w_current, fp,
                      x, y, width, height,
                      color,
                      fill_width,
                      angle1, pitch1, angle2, pitch2,
                      origin_x, origin_y);
     }

          Uses :
          o_box_print_filled,  -- o_box_basic.c - o_box_print_filled().
          o_box_print_hatch,  -- o_box_basic.c - o_box_print_hatch().
          o_box_print_mesh,  -- o_box_basic.c - o_box_print_mesh().

     }

Function o_box_print_solid()
============================

 -- Function: o_box_print_solid w_current fp x y width height color line_width length space orign_x origin_y
     This function prints the outline of a box when a solid line type is required. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp. The parameters length and space are ignored.

It uses the function o_line_print_solid() to print the outline. It performs four calls to this function, one for each of its side.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_solid()>>=
     /* PB : parameter filled removed */
     void
     o_box_print_solid(TOPLEVEL *w_current, FILE *fp,
                       int x, int y,
                       int width, int height,
                       int color,
                       int line_width, int length, int space,
                       int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, line_width);

       x1 = x;
       y1 = y - height; /* move the origin to 0, 0*/

       o_line_print_solid(w_current, fp,
                          x1, y1, x1 + width, y1,
                          color,
                          line_width, length, space,
                          origin_x, origin_y);
       o_line_print_solid(w_current, fp,
                          x1 + width, y1, x1 + width, y1 + height,
                          color,
                          line_width, length, space,
                          origin_x, origin_y);
       o_line_print_solid(w_current, fp,
                          x1 + width, y1 + height, x1, y1 + height,
                          color,
                          line_width, length, space,
                          origin_x, origin_y);
       o_line_print_solid(w_current, fp,
                          x1, y1 + height, x1, y1,
                          color,
                          line_width, length, space,
                          origin_x, origin_y);
       fprintf(fp, "grestore\n");

     }

          Defines :
          o_box_print_solid,
           -- o_box_print() - printing outline.

     }

Function o_box_print_dotted()
=============================

 -- Function: o_box_print_dotted w_current fp x y width height color line_width length space origin_x origin_y
     This function prints the outline of a box when a dotted line type is required. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp. The parameters length is ignored.

It uses the function o_line_print_dotted() to print the outline. It performs four calls to this function, one for each of its side.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_dotted()>>=
     /* PB : parameter filled removed */
     /* PB : parameter o_current removed */
     void
     o_box_print_dotted(TOPLEVEL *w_current, FILE *fp,
                        int x, int y,
                        int width, int height,
                        int color,
                        int line_width, int length, int space,
                        int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, line_width);

       x1 = x;
       y1 = y - height; /* move the origin to 0, 0*/

       o_line_print_dotted(w_current, fp,
                           x1, y1, x1 + width, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dotted(w_current, fp,
                           x1 + width, y1, x1 + width, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dotted(w_current, fp,
                           x1 + width, y1 + height, x1, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dotted(w_current, fp,
                           x1, y1 + height, x1, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       fprintf(fp, "grestore\n");

     }

          Defines :
          o_box_print_dotted,
           -- o_box_print() - printing outline.

     }

Function o_box_print_dashed()
=============================

 -- Function: o_box_print_dashed w_current fp x y width height color line_width length space origin_x origin_y
     This function prints the outline of a box when a dashed line type is required. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp.

It uses the function o_line_print_dashed() to print the outline. It performs four calls to this function, one for each of its side.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_dashed()>>=
     /* PB : parameter filled removed */
     /* PB : parameter o_current removed */
     void
     o_box_print_dashed(TOPLEVEL *w_current, FILE *fp,
                                        int x, int y,
                                        int width, int height,
                                        int color,
                                        int line_width, int length, int space,
                                        int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, line_width);

       x1 = x;
       y1 = y - height; /* move the origin to 0, 0*/

       o_line_print_dashed(w_current, fp,
                           x1, y1, x1 + width, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dashed(w_current, fp,
                           x1 + width, y1, x1 + width, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dashed(w_current, fp,
                           x1 + width, y1 + height, x1, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_dashed(w_current, fp,
                           x1, y1 + height, x1, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       fprintf(fp, "grestore\n");

     }

          Defines :
          o_box_print_dashed,
           -- o_box_print() - printing outline.

     }

Function o_box_print_center()
=============================

 -- Function: o_box_print_center w_current fp x y width height color line_width length space origin_x origin_y
     This function prints the outline of a box when a centered line type is required. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp.

It uses the function o_line_print_center() to print the outline. It performs four calls to this function, one for each of its side.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_center()>>=
     /* PB : parameter filled removed */
     /* PB : parameter o_current removed */
     void
     o_box_print_center(TOPLEVEL *w_current, FILE *fp,
                        int x, int y,
                        int width, int height,
                        int color,
                        int line_width, int length, int space,
                        int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, line_width);

       x1 = x;
       y1 = y - height; /* move the origin to 0, 0*/

       o_line_print_center(w_current, fp,
                           x1, y1, x1 + width, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_center(w_current, fp,
                           x1 + width, y1, x1 + width, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_center(w_current, fp,
                           x1 + width, y1 + height, x1, y1 + height,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       o_line_print_center(w_current, fp,
                           x1, y1 + height, x1, y1,
                           color,
                           line_width, length, space,
                           origin_x, origin_y);
       fprintf(fp, "grestore\n");

     }

          Defines :
          o_box_print_center,
           -- o_box_print() - printing outline.

     }

Function o_box_print_phantom()
==============================

 -- Function: o_box_print_phantom w_current fp x y width height color line_width length space origin_x origin_y
     This function prints the outline of a box when a phantom line type is required. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp.

It uses the function o_line_print_phantom() to print the outline. It performs four calls to this function, one for each of its side.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_phantom()>>=
     /* PB : parameter filled removed */
     /* PB : parameter o_current removed */
     void
     o_box_print_phantom(TOPLEVEL *w_current, FILE *fp,
                         int x, int y,
                         int width, int height,
                         int color,
                         int line_width, int length, int space,
                         int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, line_width);

       x1 = x;
       y1 = y - height; /* move the origin to 0, 0*/

       o_line_print_phantom(w_current, fp,
                            x1, y1, x1 + width, y1,
                            color,
                            line_width, length, space,
                            origin_x, origin_y);
       o_line_print_phantom(w_current, fp,
                            x1 + width, y1, x1 + width, y1 + height,
                            color,
                            line_width, length, space,
                            origin_x, origin_y);
       o_line_print_phantom(w_current, fp,
                            x1 + width, y1 + height, x1, y1 + height,
                            color,
                            line_width, length, space,
                            origin_x, origin_y);
       o_line_print_phantom(w_current, fp,
                            x1, y1 + height, x1, y1,
                            color,
                            line_width, length, space,
                            origin_x, origin_y);
       fprintf(fp, "grestore\n");
     }

          Defines :
          o_box_print_phantom,
           -- o_box_print() - printing outline.

     }

Function o_box_print_filled()
=============================

 -- Function: o_box_print_filled w_current fp x y width height color fill_width angle1 pitch1 angle2 pitch2 origin_x origin_y
     The function prints a filled box with a solid pattern. No outline is printed. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp. fill_width, angle1 and pitch1, angle2 and pitch2 parameters are ignored in this functions but kept for compatibility with other fill functions.

It uses the fbox postscript function defined in the file f_print.c to specify a filled box.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_filled()>>=
     void
     o_box_print_filled(TOPLEVEL *w_current, FILE *fp,
                        int x, int y,
                        int width, int height,
                        int color,
                        int fill_width,
                        int angle1, int pitch1,
                        int angle2, int pitch2,
                        int origin_x, int origin_y)
     {
       int x1, y1;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, 1);

       x1 = x;
       y1 = y-height; /* move the origin to 0, 0*/

       fprintf(fp, "newpath\n");
       fprintf(fp, "%d mils %d mils moveto\n", x1-origin_x, y1-origin_y);
       fprintf(fp, "%d mils %d mils fbox\n", width, height);
       fprintf(fp, "grestore\n");

     }

          Defines :
          o_box_print_filled,
           -- o_box_print() - printing the filling.

     }

Function o_box_print_mesh()
===========================

 -- Function: o_box_print_mesh w_current fp o_current x y width height color fill_width angle1 pitch1 angle2 pitch2 origin_x origin_y
     The function prints a meshed box. No outline is printed. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp.

The inside mesh is achieved by two successive call to the o_box_print_hatch() function, given angle1 and pitch1 the first time and angle2 and pitch2 the second time.

Negative or null values for pitch1 and/or pitch2 are not allowed as it leads to an endless loop in o_box_print_hatch.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_mesh()>>=
     void
     o_box_print_mesh(TOPLEVEL *w_current, FILE *fp,
                      int x, int y,
                      int width, int height,
                      int color,
                      int fill_width,
                      int angle1, int pitch1,
                      int angle2, int pitch2,
                      int origin_x, int origin_y)
     {
       o_box_print_hatch(w_current, fp,
                         x, y, width, height,
                         color,
                         fill_width,
                         angle1, pitch1, -1, -1,
                         origin_x, origin_y);
       o_box_print_hatch(w_current, fp,
                         x, y, width, height,
                         color,
                         fill_width,
                         angle2, pitch2, -1, -1,
                         origin_x, origin_y);

     }

          Defines :
          o_box_print_mesh,
           -- o_box_print() - printing the filling.

          Uses :
          o_box_print_hatch,  -- o_box_basic.c - o_box_print_hatch().

     }

Function o_box_print_hatch()
============================

 -- Function: o_box_print_hacth w_current fp x y width height color fill_width angle1 pitch1 angle2 pitch2 origin_x origin_y
     The function prints a hatched box. No outline is printed. The box is defined by the coordinates of its upper left corner in (x,y) and its width and height given by the width and height parameters. The postscript file is defined by the file pointer fp. fill_width, angle1, pitch1 parameters define the way the box has to be hatched. angle2 and pitch2 parameters are unused but kept for compatibility with other fill functions.

Negative or null values for pitch1 are not allowed as it leads to an endless loop.

All dimensions are in mils.

     <<o_box_basic.c : o_box_print_hatch()>>=
     void
     o_box_print_hatch(TOPLEVEL *w_current, FILE *fp,
                       int x, int y,
                       int width, int height,
                       int color,
                       int fill_width,
                       int angle1, int pitch1,
                       int angle2, int pitch2,
                       int origin_x, int origin_y)
     {
       int x3, y3, x4, y4;
       double cos_a_, sin_a_;
       double x0, y0, r;
       double x1, y1, x2, y2;
       double amin, amax, a[4], min1, min2, max1, max2;

       fprintf(fp, "gsave\n");
       if (w_current->print_color) {
         f_print_set_color(fp, color);
       }

       f_print_set_line_width(fp, fill_width);

          Defines :
          o_box_print_hatch,
           -- o_box_basic.c - o_box_print_mesh(),
           -- o_box_print() - printing the filling.

     }

The cosinus and sinus of angle1 are computed once and reused later.

     <<o_box_basic.c : o_box_print_hatch()>>+=
       cos_a_ = cos(((double) angle1) * M_PI/180);
       sin_a_ = sin(((double) angle1) * M_PI/180);

The function considers the smallest circle around the box. Its radius is given by the following relation. Its center is given by the point at the middle of the box horizontally and vertically (intersection of its two diagonals).

     <<o_box_basic.c : o_box_print_hatch()>>+=
       r = sqrt((double) (pow(width, 2) + pow(height, 2))) / 2;

       <<o_box_print_hatch() : calculating and printing the lines -- o_box_print_hatch() - calculating and printing the lines>>

       fprintf(fp, "grestore\n");

     }

When drawing a line in a circle there is two intersections. With the previously described circle, these intersections are out of the box. They can be easily calculated, the first by resolution of an equation and the second one by symetry in relation to the vertical axis going through the center of the circle.

These two points are then rotated of angle angle1 using the matrix previously mentionned.

     <<o_box_print_hatch() : calculating and printing the lines>>=
       y0 = 0;
       while(y0 < r) {
         x0 = pow(r, 2) - pow(y0, 2);
         x0 = sqrt(x0);

         x1 = (x0*cos_a_ - y0*sin_a_);
         y1 = (x0*sin_a_ + y0*cos_a_);
         x2 = ((-x0)*cos_a_ - y0*sin_a_);
         y2 = ((-x0)*sin_a_ + y0*cos_a_);

It now parametrizes the segment : first intersection is given the value of 0 and the second is given the value of 1. The four values for each intersection of the segment and the four sides (vertical or horizontal) of the box are given by the following relations :

     <<o_box_print_hatch() : calculating and printing the lines>>+=

                                                                                           if((int) (x2 - x1) != 0) {
                     a[0] = ((-width/2) - x1) / (x2 - x1);
                     a[1] = ((width/2)  - x1) / (x2 - x1);
             } else {
                     a[0] = 0; a[1] = 1;
             }

             if((int) (y2 - y1) != 0) {
                     a[2] = ((-height/2) - y1) / (y2 - y1);
                     a[3] = ((height/2)  - y1) / (y2 - y1);
             } else {
                     a[2] = 0; a[3] = 1;
             }

It now has to check which of these four values are for intersections with the sides of the box (some values may be for intersections out of the box). This is made by a min/max function.

     <<o_box_print_hatch() : calculating and printing the lines>>+=
                     if(a[0] < a[1]) {
                             min1 = a[0]; max1 = a[1];
                     } else {
                             min1 = a[1]; max1 = a[0];
                     }

                     if(a[2] < a[3]) {
                             min2 = a[2]; max2 = a[3];
                     } else {
                             min2 = a[3]; max2 = a[2];
                     }

                     amin = (min1 < min2) ? min2 : min1;
                     amin = (amin < 0) ? 0 : amin;

                     amax = (max1 < max2) ? max1 : max2;
                     amax = (amax < 1) ? amax : 1;

If the segment really go through the box it prints the line. It also take the opportunity of the symetry in the box in relation to its center to print the second line at the same time.

If there is no intersection of the segment with any of the sides, then there is no need to continue : there would be no more segment in the box to print.

     <<o_box_print_hatch() : calculating and printing the lines>>+=
                     if((amax > amin) && (amax != 1) && (amin != 0)) {
                             /* There is intersection between the line and the box edges */
                             x3 = (int) (x1 + amin*(x2 - x1));
                             y3 = (int) (y1 + amin*(y2 - y1));

                             x4 = (int) (x1 + amax*(x2 - x1));
                             y4 = (int) (y1 + amax*(y2 - y1));

                             fprintf(fp, "newpath\n");
                             fprintf(fp, "%d mils %d mils moveto\n",
                                             x3 + (x + width/2), y3 + (y - height/2));
                             fprintf(fp, "%d mils %d mils lineto\n",
                                             x4 + (x + width/2), y4 + (y - height/2));

                             fprintf(fp, "stroke\n");

                             fprintf(fp, "newpath\n");
                             fprintf(fp, "%d mils %d mils moveto\n",
                                             -x3 + (x + width/2), -y3 + (y - height/2));
                             fprintf(fp, "%d mils %d mils lineto\n",
                                             -x4 + (x + width/2), -y4 + (y - height/2));
                             fprintf(fp, "stroke\n");

                     } else {
                             break;
                     }

                     y0 = y0 + pitch1;
             }

Function o_box_print_old()
==========================

 -- Function: o_box_print_old w_current fp o_current origin_x origin_y
     This function is the old function to print a box. It does not handle line type and filling of a box.

     <<o_box_basic.c : o_box_print_old()>>=
     void
     o_box_print_old(TOPLEVEL *w_current, FILE *fp,
                     int origin_x, int origin_y)
     {
       int width, height;
       int x1, y1;
       if (o_current == NULL) {
         printf("got null in o_box_print\n");
         return;
       }

       if (w_current->print_color) {
         f_print_set_color(fp, o_current->color);
       }

       width = abs(o_current->line_points->x2 - o_current->line_points->x1);
       height = abs(o_current->line_points->y1 - o_current->line_points->y2);

       x1 = o_current->line_points->x1;
       y1 = o_current->line_points->y1-height; /* move the origin to 0, 0*/

       fprintf(fp, "newpath\n");
       fprintf(fp, "%d mils %d mils moveto\n", x1-origin_x, y1-origin_y);
       fprintf(fp, "%d mils %d mils box\n", width, height);

     }

          Defines :
          .

          Uses :
          o_box_print,  -- o_box_basic.c - o_box_print().

     }

Function o_box_image_write()
============================

 -- Function: o_box_image_write w_current o_current origin_x origin_y color_mode
     This function draws a box in an image with the libgdgeda function gdImageRectangle().

     <<o_box_basic.c : o_box_image_write()>>=
     void
     o_box_image_write(TOPLEVEL *w_current, OBJECT *o_current,
                       int origin_x, int origin_y, int color_mode)
     {
       int color;

       if (o_current == NULL) {
         printf("got null in o_box_image_write\n");
         return;
       }

       if (color_mode == TRUE) {
         color = o_image_geda2gd_color(o_current->color);
       } else {
         color = image_black;
       }

       /* assumes screen coords are already calculated correctly */
     #ifdef HAS_LIBGDGEDA

       gdImageSetThickness(current_im_ptr, SCREENabs(w_current,
                                                     o_current->line_width));

       gdImageRectangle(current_im_ptr,
                        o_current->box->screen_upper_x,
                        o_current->box->screen_upper_y,
                        o_current->box->screen_lower_x,
                        o_current->box->screen_lower_y,
                        color);
     #endif

     }

          Defines :
          .

     }