#include #include "ebs.h" #include "cgm.h" enum error_class {none, warning, error}; /* Turn on Debug for log infos on stderr */ #ifdef DEBUG #define dprintf(X) printf X #else #define dprintf(X) #endif /* DEBUG */ #define NO_DIAGRAM "No Location Diagram" /* ISO 2022 7-bit character set SI/SO functions */ #define SI 15 #define SO 14 /* CGM Opcodes */ #define CGM_NOP (0 << 12 | 0 << 5) #define CGM_BEGMF (0 << 12 | 1 << 5) #define CGM_ENDMF (0 << 12 | 2 << 5) #define CGM_BEGPIC (0 << 12 | 3 << 5) #define CGM_BEGPICBODY (0 << 12 | 4 << 5) #define CGM_ENDPIC (0 << 12 | 5 << 5) #define CGM_MFVERSION (1 << 12 | 1 << 5) #define CGM_MFELEMLIST (1 << 12 | 11 << 5) #define CGM_VDCEXT (2 << 12 | 6 << 5) #define CGM_LINE (4 << 12 | 1 << 5) #define CGM_POLYGON (4 << 12 | 7 << 5) #define CGM_LINECOLOR (5 << 12 | 4 << 5) #define CGM_FILLCOLOR (5 << 12 | 23 << 5) #define CGM_EDGECOLOR (5 << 12 | 29 << 5) #define CGM_TEXTCOLOR (5 << 12 | 14 << 5) #define CGM_MARKERCOLOR (5 << 12 | 8 << 5) #define CGM_SYMBOLCOLOR (5 << 12 | 49 << 5) #define CGM_BACKGROUNDCOLOR (2 << 12 | 7 << 5) #define BLOCKSIZE 100 extern void checkfree (void *ptr); extern char *checkstrdup (char *ptr); extern char *checkmalloc (unsigned int len); extern void *checkrealloc (void *ptr_in, int size); static void draw_locations_internal (anat_dia *diagram); static struct opcode_info { int remaining; int cont; char *act; char *last; enum error_class error; } opcode_info; char aux_buffer [10000]; static void notice (anat_dia *diagram, enum error_class error) { if (opcode_info.error!= none) return; if (error== warning) GNotice (diagram, "warning: illegal CGM element(s)"); else GNotice (diagram, "error: illegal CGM file"); opcode_info.error= error; } void init_anat_dia_int (anat_dia *diagram, int paint_channel_dot, GetChannelLabelProc labelproc, YourRepaintProcInt repproc) { diagram->name= NULL; diagram->version= -1; diagram->first_picture= NULL; diagram->pic = NULL; diagram->npictures= 0; diagram->actpic= -1; diagram->factor = 1; diagram->xoffset = 0; diagram->yoffset = 0; diagram->content= NULL; diagram->content_length= 0; diagram->paint_channel_dot= paint_channel_dot; diagram->background= 0; /* white */ diagram->cgm_linecolor= -1; diagram->cgm_edgecolor= -1; diagram->cgm_fillcolor= -1; diagram->cgm_textcolor= -1; diagram->cgm_symbolcolor= -1; diagram->cgm_markercolor= -1; diagram->cgm_backgroundcolor= -1; diagram->repproc= repproc; /* For CHANNEL_LOCATIONS */ diagram->location= NULL; diagram->nlocations= 0; diagram->labelproc= labelproc; } void delete_anat_dia_int (anat_dia *diagram) { delete_cgm_metafile (diagram); } void set_width_height (anat_dia *diagram, int width, int height) { diagram->width= width; diagram->height= height; } /*************************************************************************** Some useful functions ***************************************************************************/ /* * Transforms a 7-bit string seven, in which the ASCII control characters * SI and SO are used to activate and deactivate the G1 set (characters * 160 - 255) into an 8-bit string eight without SI and SO characters. * Return value is strlen(eight). */ static int seven2eight(unsigned char *eight, const unsigned char *seven, int maxlen) { int g = 0, i = 0; while (*seven && maxlen) { if (*seven == SI) g = 128; else if (*seven == SO) g = 0; else { i++; maxlen--; if (*seven < 128 && *seven > 31) *(eight++) = *seven + g; else *(eight++) = *seven; } seven++; } *eight = 0; return i; } /* * Transforms an 8-bit string into a 7-bit string in which the G1 * characters are switched into the G0 area with SI and are deactivated * with SO. The return value is strlen(seven) <= strlen(eight)*2. */ static int eight2seven(unsigned char *seven, const unsigned char *eight) { int g = 0, i = 0; while (*eight) { if (*eight > 127 & !g) *(seven++) = SI, i++, g = 128; else if (*eight < 128 && g) *(seven++) = SO, i++, g = 0; *(seven++) = *(eight++) - g; i++; } *seven = 0; return i; } /* * Free cgm data and channel positions */ void delete_cgm_metafile (anat_dia *diagram) { cgm_picture *picture = diagram->first_picture, *next; while (picture) { cgm_gpe *gpe = picture->first_gpe, *next_gpe; while (gpe) { next_gpe = gpe->next_gpe; checkfree(gpe->arg); checkfree(gpe); gpe = next_gpe; } next = picture->next_picture; checkfree(picture->name); checkfree(picture->cgm_color); checkfree(picture); picture = next; } checkfree(diagram->name); diagram->name= NULL; diagram->first_picture = NULL; checkfree (diagram->content); diagram->content= NULL; diagram->content_length= 0; diagram->pic = NULL; diagram->npictures= 0; delete_channel_locations (diagram); } /* Check if color already allocated, return index of colorcell */ int AddCGMColor (struct cgm_picture *pic, int red, int green, int blue) { int i; for (i= 0; i< pic->ncgm_colors; ++i) if (pic->cgm_color [i].red== red && pic->cgm_color [i].green== green && pic->cgm_color [i].blue== blue) return (i); pic->cgm_color= (GColor *) checkrealloc (pic->cgm_color, (pic->ncgm_colors+ 1)* sizeof (GColor)); pic->cgm_color [pic->ncgm_colors].red= red; pic->cgm_color [pic->ncgm_colors].green= green; pic->cgm_color [pic->ncgm_colors].blue= blue; return (pic->ncgm_colors++); } /*************************************************************************** Functions for encoding and decoding binary CGM Files ***************************************************************************/ static int rewind_cgm_metafile (void *ptr, unsigned long length) { opcode_info.remaining= 0; opcode_info.cont= 0; opcode_info.act= ptr; opcode_info.last= ((char *) ptr)+ length; opcode_info.error= none; } static unsigned int get_opcode (void) { int opcode, len, value; /* if (opcode_info.remaining!= 0) { fprintf (stderr, "remaining!= 0\n"); exit (1); } if (opcode_info.cont) { fprintf (stderr, "cont\n"); exit (1); } if (opcode_info.act>= opcode_info.last) { fprintf (stderr, "act>= last\n"); exit (1); } */ if ((int) opcode_info.act & 1) opcode_info.act++; /* skip padding byte */ value= (geti16((void **) &opcode_info.act) & 0xffff); opcode= (value & 0xffe0); if ((value & 0x1f) == 0x1f) { len = geti16 ((void **) &opcode_info.act); /* printf ("long\n"); */ } else len = (value & 0x1f); opcode_info.remaining= len & ~0x8000; opcode_info.cont= len & 0x8000; /* printf ("%X Opcode %X, len %d, cont %d\n", value, opcode, opcode_info.remaining, opcode_info.cont); */ return (opcode); } static void skip_until_opcode (void) { int value; opcode_info.act+= opcode_info.remaining; if ((int) opcode_info.act & 1) opcode_info.act++; /* skip padding byte */ while (opcode_info.cont) { value= (geti16((void **) &opcode_info.act) & 0xffff); opcode_info.remaining= value & ~0x8000; opcode_info.cont= value & 0x8000; opcode_info.act+= opcode_info.remaining; if ((int) opcode_info.act & 1) opcode_info.act++; /* skip padding byte */ } opcode_info.remaining= 0; opcode_info.cont= 0; /* printf ("skipped\n"); */ } static char get_int8 (void) { if (opcode_info.remaining<= 0 && !opcode_info.cont) { return (0); fprintf (stderr, "pointer past end\n"); exit (1); } if (opcode_info.remaining== 0) { /* && opcode_info.cont, look above */ unsigned int value; value= (geti16((void **) &opcode_info.act) & 0xffff); opcode_info.remaining= value & ~0x8000; opcode_info.cont= value & 0x8000; } opcode_info.remaining--; /* printf ("Zeichen %c, rem %d\n", *opcode_info.act, opcode_info.remaining); */ return (*opcode_info.act++); } static int get_int16 (void) { if (opcode_info.remaining<= 0 && !opcode_info.cont) { return (0); fprintf (stderr, "pointer past end\n"); exit (1); } if (opcode_info.remaining== 0) { /* && opcode_info.cont, look above */ unsigned int value; value= (geti16 ((void **) &opcode_info.act) & 0xffff); opcode_info.remaining= value & ~0x8000; opcode_info.cont= value & 0x8000; } opcode_info.remaining-= 2; /* printf ("Zahl %02X%02X, rem %d\n", *opcode_info.act, *(opcode_info.act+1), opcode_info.remaining); */ return (geti16 ((void **) &opcode_info.act)); } static int finished (void) { return (opcode_info.remaining== 0 && !opcode_info.cont); } /* * Decode a cgm picture body */ static void read_cgm_picture_body (cgm_picture *picture, anat_dia *diagram) { cgm_gpe *gpe = NULL; int opcode, len, cont = 0, i, next= 0; /* Read control elements or graphical primitives */ picture->first_gpe = (cgm_gpe *) checkmalloc(sizeof(cgm_gpe)); gpe = picture->first_gpe; while ((opcode = get_opcode()) != CGM_ENDPIC) { if (next) { gpe->next_gpe = (cgm_gpe *) checkmalloc(sizeof(cgm_gpe)); gpe = gpe->next_gpe; } gpe->type= -1; gpe->arg= NULL; gpe->arg_len= 0; next= 0; switch (opcode) { case CGM_LINE: case CGM_POLYGON: { GPoint *points = (GPoint *) checkmalloc(BLOCKSIZE * sizeof(GPoint)); int remaining, i; remaining= BLOCKSIZE; i= 0; do { if (remaining== 0) { points = (GPoint *) checkrealloc(points, (i+ BLOCKSIZE) * sizeof(GPoint)); remaining= BLOCKSIZE; } points[i].x = get_int16(); points[i].y = get_int16(); i++; remaining--; } while (!finished()); /* Fill gpe structure */ gpe->type = opcode; gpe->arg = (void *) checkrealloc (points, i* sizeof(GPoint)); gpe->arg_len= i; } next= 1; break; case CGM_LINECOLOR: case CGM_FILLCOLOR: case CGM_EDGECOLOR: case CGM_MARKERCOLOR: case CGM_TEXTCOLOR: case CGM_SYMBOLCOLOR: { int r, g, b; int *colorno= (int *) checkmalloc (sizeof (int)); r= get_int16 (); g= get_int16 (); b= get_int16 (); *colorno= AddCGMColor (picture, r, g, b); /* Fill gpe structure */ gpe->type = opcode; gpe->arg = (void *) colorno; gpe->arg_len= 1; } next= 1; break; case CGM_NOP: dprintf(("NOP\n")); break; default: dprintf(("ERROR: unknown element: class %d, code: %d\n", \ opcode>>12, (opcode>>5) & 0177)); notice (diagram, warning); skip_until_opcode(); break; } } picture->next_picture = NULL; gpe->next_gpe = NULL; } /* * Decode a cgm picture */ static void read_cgm_picture(cgm_picture *picture, anat_dia *diagram) { int opcode; picture->first_gpe = NULL; picture->cgm_color= NULL; picture->ncgm_colors= 0; picture->background= -1; /* Read picture descriptors */ while ((opcode = get_opcode()) != CGM_ENDPIC) { switch (opcode) { case CGM_VDCEXT: dprintf(("VDC EXTENT\n")); picture->min_x = get_int16(); picture->min_y = get_int16(); picture->max_x = get_int16(); picture->max_y = get_int16(); dprintf(("(%d, %d) ", picture->min_x, picture->min_y)); dprintf(("(%d, %d)\n", picture->max_x, picture->max_y)); break; case CGM_BEGPICBODY: dprintf(("BEGPICBODY\n")); read_cgm_picture_body(picture, diagram); return; break; case CGM_BACKGROUNDCOLOR: { int r, g, b; r= get_int16 (); g= get_int16 (); b= get_int16 (); picture->background= AddCGMColor (picture, r, g, b); } break; case CGM_NOP: dprintf(("NOP\n")); break; default: dprintf(("ERROR: unknown element: class %d, code: %d\n", \ opcode>>12, (opcode>>5) & 0177)); notice (diagram, warning); skip_until_opcode(); break; } } } /* * Decode a cgm diagram */ void read_cgm_metafile (char *ptr, unsigned long length, struct anat_dia *diagram) { cgm_picture *picture = NULL; int opcode = 0, len = 0, i; rewind_cgm_metafile (ptr, length); delete_cgm_metafile (diagram); /* BEGIN DIAGRAM */ if (get_opcode() != CGM_BEGMF) { notice(diagram, error); return; } i= 0; while (!finished ()) aux_buffer [i++]= get_int8 (); aux_buffer [i]= '\0'; diagram->name = checkstrdup(aux_buffer); dprintf(("BEGMF: %s\n", diagram->name)); /* DIAGRAM VERSION */ if (get_opcode() != CGM_MFVERSION) { notice(diagram, error); return; } diagram->version = get_int16(); if ((diagram->version < 1) || (diagram->version > 3)) { notice(diagram, error); return; } dprintf(("MFVERSION: %d\n", diagram->version)); /* Read diagram descriptors */ while ((opcode = get_opcode()) != CGM_ENDMF) { switch (opcode) { case CGM_MFELEMLIST: dprintf(("MFELEMLIST\n")); /* Nieder mit ISO/IEC!!! */ len= get_int16 (); opcode_info.act+= len* 4; opcode_info.remaining= 0; opcode_info.cont= 0; break; while (!finished ()) { int a; a= get_int16() << 12; a|= get_int16() << 5; switch (a & 0xffff) { case CGM_BEGPIC: case CGM_BEGPICBODY: case CGM_ENDPIC: case CGM_VDCEXT: case CGM_LINE: /* OK */ break; default: notice (diagram, warning); break; } } break; case CGM_BEGPIC: if (! diagram->first_picture) { diagram->first_picture = (cgm_picture *) checkmalloc(sizeof(cgm_picture)); picture = diagram->first_picture; picture->next_picture= NULL; } else { picture->next_picture = (cgm_picture *) checkmalloc(sizeof(cgm_picture)); picture = picture->next_picture; } i= 0; while (!finished ()) aux_buffer [i++]= get_int8 (); aux_buffer [i]= '\0'; picture->name = checkmalloc(i+1); seven2eight(picture->name, aux_buffer, i); dprintf(("BEGPIC: %s\n", picture->name)); diagram->npictures++; read_cgm_picture(picture, diagram); break; case CGM_NOP: dprintf(("NOP\n")); break; default: dprintf(("ERROR: unknown element: class %d, code: %d\n", \ opcode>>12, (opcode>>5) & 0177)); notice (diagram, warning); skip_until_opcode(); break; } } dprintf(("ENDMF\n")); diagram->content= checkmalloc (length); memcpy (diagram->content, ptr, length); diagram->content_length= length; diagram->pic= diagram->first_picture; } #if 0 /* * Put the opcode and the length of a binary coded cgm element */ static long put_opcode(int opcode, int length, void **pptr) { long bytes; if (length < 0x1f) { puti16(opcode | length, pptr); bytes = 2; } else { puti16(opcode | 0x1f, pptr); puti16(length, pptr); bytes = 4; } return bytes; } /* * Encode a cgm picture */ static void write_cgm_picture_body(cgm_picture *picture, void **pptr, unsigned long *len) { cgm_gpe *gpe = picture->first_gpe; int i; /* Write graphical primitives */ while (gpe) { switch (gpe->type) { case CGM_LINE: { GPoint *points = (GPoint *) gpe->arg; *len += put_opcode(CGM_LINE, gpe->arg_len*4, pptr); dprintf(("LINE\n")); for (i=0; iarg_len; i++) { puti16(points[i].x, pptr); puti16(points[i].y, pptr); dprintf(("(%d, %d) ", points[i].x, points[i].y)); } dprintf(("\n")); *len += gpe->arg_len*4; } break; } gpe = gpe->next_gpe; } /* END PICTURE */ *len += put_opcode(CGM_ENDPIC, 0, pptr); dprintf(("ENDPIC\n")); return; } /* * Encode a cgm picture */ static void write_cgm_picture(cgm_picture *picture, void **pptr, unsigned long *len) { unsigned char namebuf[BUFFER_SIZE]; char blank = '\0'; int namelen, i; eight2seven(picture->name, namebuf); namelen = strlen((char *) namebuf) + 1; if (namelen == 0) { *len += put_opcode(CGM_BEGPIC, 1, pptr); memcpy((char *)*pptr, &blank, 1); } else { *len += put_opcode(CGM_BEGPIC, namelen, pptr); memcpy((char *)*pptr, namebuf, namelen); } if (namelen % 2) { memcpy((char *)*pptr, &blank, 1); namelen++; } for (i=0; iname)); /* VDC EXTENT */ *len += put_opcode(CGM_VDCEXT, 8, pptr); puti16(picture->min_x, pptr); puti16(picture->min_y, pptr); puti16(picture->max_x, pptr); puti16(picture->max_y, pptr); *len += 8; dprintf(("VDC_EXTENT\n")); dprintf(("(%d, %d) ", picture->min_x, picture->min_y)); dprintf(("(%d, %d)\n", picture->max_x, picture->max_y)); /* BEGIN PICTURE BODY */ *len += put_opcode(CGM_BEGPICBODY, 0, pptr); dprintf(("BEGPICBODY\n")); write_cgm_picture_body(picture, pptr, len); return; } /* * Encode a cgm diagram */ static void write_cgm_metafile(void **pptr, unsigned long *len) { cgm_picture *picture = diagram.first_picture; char blank = '\0'; int namelen = strlen(diagram.name), i; /* BEGIN DIAGRAM */ if (namelen == 0) { *len += put_opcode(CGM_BEGMF, 1, pptr); memcpy((char *)*pptr, &blank, 1); namelen++; } else { *len += put_opcode(CGM_BEGMF, namelen, pptr); memcpy((char *)*pptr, diagram.name, namelen); } if (namelen % 2) { memcpy((char *)*pptr, &blank, 1); namelen++; } for (i=0; inext_picture; } /* END DIAGRAM */ *len += put_opcode(CGM_ENDMF, 0, pptr); dprintf(("ENDMF\n")); /* zero padding */ if ((*len & 3) != 0) { puti16(0, pptr); *len += 2; } return; } #endif char *get_anat_dia_picture_name (anat_dia *diagram) { if (diagram->pic== NULL) return (NULL); return (diagram->pic->name); } int get_anat_dia_npictures (anat_dia *diagram) { return (diagram->npictures); } void get_cgm_metafile (void **pptr, unsigned long *len, struct anat_dia *diagram) { *pptr= diagram->content; *len= diagram->content_length; } /* * Conversion of coordinates from VDC representation * to X representation and vice versa. */ int vdc2x_x (int x, anat_dia *diagram) { float xpos = diagram->factor * (x - diagram->pic->min_x); return (diagram->xoffset + rint(xpos)); } int vdc2x_y (int y, anat_dia *diagram) { float ypos = diagram->factor * (y - diagram->pic->min_y); return (diagram->height - diagram->yoffset - rint(ypos)); } int x2vdc_x (int x, anat_dia *diagram) { float xpos = (x - diagram->xoffset) / diagram->factor; return (diagram->pic->min_x + rint(xpos)); } int x2vdc_y (int y, anat_dia *diagram) { float ypos = (diagram->height - y - diagram->yoffset) / diagram->factor; return (diagram->pic->min_y + rint(ypos)); } int in_subwindow_vdc (int x, int y, anat_dia *diagram) { x= vdc2x_x (x, diagram); y= vdc2x_y (y, diagram); return !(x< diagram->xoffset || x> diagram->width- diagram->xoffset || y< diagram->yoffset || y> diagram->height- diagram->yoffset); } int in_subwindow_x (int x, int y, anat_dia *diagram) { return !(x< diagram->xoffset || x> diagram->width- diagram->xoffset || y< diagram->yoffset || y> diagram->height- diagram->yoffset); } /* * Calculate the scaling factor */ static void calc_factor (anat_dia *diagram) { double width = (diagram->pic ? diagram->pic->max_x - diagram->pic->min_x : 1), height = (diagram->pic ? diagram->pic->max_y - diagram->pic->min_y : 1), xfactor, yfactor; xfactor = ((double) diagram->width) / width; yfactor = ((double) diagram->height) / height; if (fabs(xfactor) < fabs(yfactor)) { diagram->xoffset= 0; diagram->yoffset= rint((diagram->height - (xfactor * height)) / 2); diagram->factor = xfactor; } else { diagram->xoffset= rint((diagram->width - (yfactor * width)) / 2); diagram->yoffset= 0; diagram->factor = yfactor; } } void repaint_anat_dia (anat_dia *diagram) { cgm_gpe *gpe; int i; GClearWindow (diagram); if (diagram->pic== NULL) { GDrawImageString(diagram, CGM_FOREGROUND, (diagram->width / 2) - 50, (diagram->height / 2), NO_DIAGRAM); return; } dprintf(("\nREPAINT\n")); calc_factor(diagram); diagram->cgm_linecolor= -1; diagram->cgm_edgecolor= -1; diagram->cgm_fillcolor= -1; diagram->cgm_textcolor= -1; diagram->cgm_symbolcolor= -1; diagram->cgm_markercolor= -1; diagram->cgm_backgroundcolor= -1; GDrawRectangle(diagram, CGM_FOREGROUND, vdc2x_x(diagram->pic->min_x, diagram), vdc2x_y(diagram->pic->max_y, diagram), (unsigned int) vdc2x_x(diagram->pic->max_x, diagram) - vdc2x_x(diagram->pic->min_x, diagram), (unsigned int) vdc2x_y(diagram->pic->min_y, diagram) - vdc2x_y(diagram->pic->max_y, diagram)); gpe = diagram->pic->first_gpe; while (gpe) { switch (gpe->type) { case CGM_LINE: { GPoint *points = (GPoint *) gpe->arg; int len = gpe->arg_len; for (i=0; iarg, *result; int len = gpe->arg_len; result= (GPoint *) checkmalloc (len* sizeof (GPoint)); for (i=0; i< len; i++) { /* Translate coordinates */ result [i].x= vdc2x_x (points[i].x, diagram); result [i].y= vdc2x_y (points[i].y, diagram); } GFillPolygon (diagram, CGM_FILL, result, len); if (diagram->cgm_fillcolor!= diagram->cgm_edgecolor) GDrawLines (diagram, CGM_EDGE, result, len); checkfree (result); } break; case CGM_LINECOLOR: diagram->cgm_linecolor= *((int *) (gpe->arg)); GSetForeground (diagram, CGM_LINE, diagram->cgm_linecolor); break; case CGM_EDGECOLOR: diagram->cgm_edgecolor= *((int *) (gpe->arg)); GSetForeground (diagram, CGM_EDGE, diagram->cgm_edgecolor); break; case CGM_FILLCOLOR: diagram->cgm_fillcolor= *((int *) (gpe->arg)); GSetForeground (diagram, CGM_FILL, diagram->cgm_fillcolor); break; } gpe = gpe->next_gpe; } draw_locations_internal (diagram); if (diagram->repproc!= NULL) diagram->repproc (diagram); } void set_anat_dia_background (int color, anat_dia *diagram) { if (color!= 1 && color!= 0) return; if (diagram->pic== NULL) return; if (diagram->background< 0) return; diagram->background= color; set_anat_dia_picture (-1, diagram); } void set_anat_dia_picture (int no, anat_dia *diagram) { int i; if (!(no== -1 && diagram->pic!= NULL)) { if (no< 0 || no>= diagram->npictures) { repaint_anat_dia (diagram); return; } diagram->pic= diagram->first_picture; diagram->actpic= no; for (i= 0; i< no; ++i) diagram->pic= diagram->pic->next_picture; } GSetColors (diagram, no, diagram->pic->cgm_color, diagram->pic->ncgm_colors, diagram->pic->background); /* Unmark all channel locations */ unmark_channel_locations (diagram); repaint_anat_dia (diagram); } /* Subroutine for CHANNEL_LOCATIONS */ void delete_channel_locations (anat_dia *diagram) { checkfree (diagram->location); diagram->location= NULL; diagram->nlocations= 0; } void read_channel_locations (void *ptr, unsigned long length, int nchans, anat_dia *diagram) { int i, npics, j; if ((length % 6)!= 0) { delete_channel_locations (diagram); return; } diagram->nlocations= length/ 6; diagram->location= (location *) checkmalloc (diagram->nlocations* sizeof (location)); npics= get_anat_dia_npictures (diagram); calc_factor(diagram); j= 0; for (i=0; i< length / 6; i++) { diagram->location [j].chn_number = geti32(&ptr); diagram->location [j].pic_number = geti32(&ptr); diagram->location [j].x1 = geti32(&ptr); diagram->location [j].y1 = geti32(&ptr); diagram->location [j].x2 = geti32(&ptr); diagram->location [j].y2 = geti32(&ptr); if (diagram->location [j].pic_number < npics && diagram->location [j].chn_number < nchans && in_subwindow_vdc (diagram->location [j].x1, diagram->location [j].y1, diagram)) if (diagram->location [j].x2!= COORD_UNDEFINED && diagram->location [j].y2!= COORD_UNDEFINED) { if (in_subwindow_vdc (diagram->location [j].x2, diagram->location [j].y2, diagram)) j++; } else j++; } diagram->nlocations= j; if (j== 0) delete_channel_locations (diagram); else diagram->location= (location *) checkrealloc (diagram->location, j* sizeof (location)); } void get_channel_locations (location **loc, unsigned long *no, anat_dia *diagram) { *loc= diagram->location; *no= diagram->nlocations; } void unmark_channel_locations (anat_dia *diagram) { int i; for (i= 0; i< diagram->nlocations; ++i) diagram->location[i].marked= 0; draw_locations_internal (diagram); } void delete_marked_locations (anat_dia *diagram) { int target=0, i; for (i= 0; i< diagram->nlocations; ++i) if (!diagram->location[i].marked || diagram->location[i].pic_number!= diagram->actpic) { if (i!= target) diagram->location[target]= diagram->location[i]; ++target; } if (diagram->nlocations== target) return; diagram->nlocations= target; if (target== 0) delete_channel_locations (diagram); else diagram->location= (location *) checkrealloc (diagram->location, target* sizeof (location)); /* repaint canvas */ repaint_anat_dia (diagram); } void mark_locations_within_x (int x1, int y1, int x2, int y2, anat_dia *diagram) { int i, m; x1= x2vdc_x (x1, diagram); x2= x2vdc_x (x2, diagram); y1= x2vdc_y (y1, diagram); y2= x2vdc_y (y2, diagram); if (x2< x1) {m= x1; x1= x2; x2= m;} if (y2< y1) {m= y1; y1= y2; y2= m;} for (i= 0; i< diagram->nlocations; ++i) { if (diagram->location[i].pic_number== diagram->actpic && diagram->location[i].x1>= x1 && diagram->location[i].x1<= x2 && diagram->location[i].y1>= y1 && diagram->location[i].y1<= y2) diagram->location[i].marked|= 1; if (x2!= COORD_UNDEFINED && y2!= COORD_UNDEFINED && diagram->location[i].x2>= x1 && diagram->location[i].x2<= x2 && diagram->location[i].y2>= y1 && diagram->location[i].y2<= y2) diagram->location[i].marked|= 2; } draw_locations_internal (diagram); } void mark_unmark_locations_around_x (int x, int y, anat_dia *diagram) { int x1, y1, x2, y2, m, i; x1= x2vdc_x (x- 8, diagram); x2= x2vdc_x (x+ 8, diagram); y1= x2vdc_y (y+ 8, diagram); y2= x2vdc_y (y- 8, diagram); if (x2< x1) {m= x1; x1= x2; x2= m;} if (y2< y1) {m= y1; y1= y2; y2= m;} for (i= 0; i< diagram->nlocations; ++i) { if (diagram->location[i].pic_number== diagram->actpic && diagram->location[i].x1>= x1 && diagram->location[i].x1<= x2 && diagram->location[i].y1>= y1 && diagram->location[i].y1<= y2) diagram->location[i].marked^= 1; if (x2!= COORD_UNDEFINED && y2!= COORD_UNDEFINED && diagram->location[i].x2>= x1 && diagram->location[i].x2<= x2 && diagram->location[i].y2>= y1 && diagram->location[i].y2<= y2) diagram->location[i].marked^= 2; } draw_locations_internal (diagram); } int around_marked (int x, int y, anat_dia *diagram) { int x1, x2, y1, y2, i, d; d= 8/ diagram->factor; x1= x- d; y1= y- d; x2= x+ d; y2= y+ d; for (i= 0; i< diagram->nlocations; ++i) { if (diagram->location[i].pic_number== diagram->actpic && diagram->location[i].marked & 1 && diagram->location[i].x1>= x1 && diagram->location[i].x1<= x2 && diagram->location[i].y1>= y1 && diagram->location[i].y1<= y2) return (1); if (x2!= COORD_UNDEFINED && y2!= COORD_UNDEFINED && diagram->location[i].marked & 2 && diagram->location[i].x2>= x1 && diagram->location[i].x2<= x2 && diagram->location[i].y2>= y1 && diagram->location[i].y2<= y2) return (1); } return (0); } location *get_first_marked (anat_dia *diagram) { int i; for (i= 0; i< diagram->nlocations; ++i) if (diagram->location[i].marked && diagram->location[i].pic_number== diagram->actpic) { diagram->actlocation= i; return (&diagram->location[i]); } return (NULL); } location *get_next_marked (anat_dia *diagram) { int i; if (diagram->actlocation< 0) diagram->actlocation= -1; for (i= diagram->actlocation+1; i< diagram->nlocations; ++i) if (diagram->location[i].marked && diagram->location[i].pic_number== diagram->actpic) { diagram->actlocation= i; return (&diagram->location[i]); } return (NULL); } void append_locations (location *loc_new, int no, anat_dia *diagram) { int i; if (no<= 0) return; diagram->location= (location *) checkrealloc (diagram->location, (diagram->nlocations+ no)* sizeof (location)); /* Unmark all previousy marked locations */ for (i= 0; i< diagram->nlocations; ++i) diagram->location[i].marked= 0; for (i= 0; i< no; ++i) { /* mark all locations */ loc_new[i].marked= 1; if (loc_new[i].x2!= COORD_UNDEFINED && loc_new[i].y2!= COORD_UNDEFINED) loc_new[i].marked|= 2; loc_new[i].pic_number= diagram->actpic; diagram->location [diagram->nlocations+ i]= loc_new [i]; } diagram->nlocations+= no; draw_locations_internal (diagram); } static void draw_locations_internal (anat_dia *diagram) { char *string; GPoint vert[3]; int i; /* Draw all channel locations */ if (diagram->location== NULL) return; for (i= 0; i< diagram->nlocations; ++i) { if (diagram->location[i].pic_number!= diagram->actpic) continue; if (diagram->paint_channel_dot) { /* Background */ GFillRectangle(diagram, CGM_BACKGROUND, vdc2x_x(diagram->location[i].x1, diagram)-6, vdc2x_y(diagram->location[i].y1, diagram)-6, 13, 13); /* Foreground */ GFillRectangle(diagram, CGM_FOREGROUND, vdc2x_x(diagram->location[i].x1, diagram)-3, vdc2x_y(diagram->location[i].y1, diagram)-3, 7, 7); } if (diagram->location[i].x2!= COORD_UNDEFINED && diagram->location[i].y2!= COORD_UNDEFINED) { /* Arrow */ int x1 = vdc2x_x(diagram->location[i].x1, diagram), y1 = vdc2x_y(diagram->location[i].y1, diagram), x2 = vdc2x_x(diagram->location[i].x2, diagram), y2 = vdc2x_y(diagram->location[i].y2, diagram); double vector_x = x2 - x1, /* Compute the vector from P1 to P2 */ vector_y = y2 - y1, vector_len = sqrt(vector_x * vector_x + vector_y * vector_y); if (vector_len>= 10) { /* Normalize the vector */ vector_x = vector_x / vector_len; vector_y = vector_y / vector_len; /* Compute the corners of the arrow's head */ vert[0].x = x2 - (vector_x*3); vert[0].y = y2 - (vector_y*3); vert[1].x = x2 - 20*vector_x + 5*vector_y; vert[1].y = y2 - 20*vector_y - 5*vector_x; vert[2].x = x2 - 20*vector_x - 5*vector_y; vert[2].y = y2 - 20*vector_y + 5*vector_x; /* Draw second point */ /* Background */ GFillRectangle(diagram, CGM_BACKGROUND, x2-6, y2-6, 13, 13); /* Foreground */ GFillRectangle(diagram, CGM_FOREGROUND, x2-3, y2-3, 7, 7); GFillPolygon(diagram, CGM_FOREGROUND,vert, 3); GDrawLine(diagram, CGM_FOREGROUND, x1, y1, x2 - 20*vector_x, y2 - 20*vector_y); } } string= diagram->labelproc (&diagram->location[i]); if (string!= NULL && *string!= '\0') GDrawImageString(diagram, CGM_FOREGROUND, vdc2x_x(diagram->location[i].x1, diagram) + 8, vdc2x_y(diagram->location[i].y1 - 3, diagram), string); if (diagram->location [i].marked & 1) GDrawRectangle(diagram, CGM_FOREGROUND, vdc2x_x(diagram->location[i].x1, diagram)-5, vdc2x_y(diagram->location[i].y1, diagram)-5, 10, 10); if ((diagram->location [i].marked & 2) && diagram->location [i].x2!= COORD_UNDEFINED && diagram->location [i].y2!= COORD_UNDEFINED) GDrawRectangle(diagram, CGM_FOREGROUND, vdc2x_x(diagram->location[i].x2, diagram)-5, vdc2x_y(diagram->location[i].y2, diagram)-5, 10, 10); } } void draw_location (location *location, anat_dia *diagram) { char *string; GPoint vert[3]; if (location->pic_number!= diagram->actpic) return; /* Foreground */ GFillRectangle(diagram, CGM_XOR, vdc2x_x(location->x1, diagram)-3, vdc2x_y(location->y1, diagram)-3, 7, 7); if (location->x2!= COORD_UNDEFINED && location->y2!= COORD_UNDEFINED) { /* Arrow */ int x1 = vdc2x_x(location->x1, diagram), y1 = vdc2x_y(location->y1, diagram), x2 = vdc2x_x(location->x2, diagram), y2 = vdc2x_y(location->y2, diagram); double vector_x = x2 - x1, /* Compute the vector from P1 to P2 */ vector_y = y2 - y1, vector_len = sqrt(vector_x * vector_x + vector_y * vector_y); if (vector_len>= 10) { /* Normalize the vector */ vector_x = vector_x / vector_len; vector_y = vector_y / vector_len; /* Compute the corners of the arrow's head */ vert[0].x = x2 - (vector_x*3); vert[0].y = y2 - (vector_y*3); vert[1].x = x2 - 20*vector_x + 5*vector_y; vert[1].y = y2 - 20*vector_y - 5*vector_x; vert[2].x = x2 - 20*vector_x - 5*vector_y; vert[2].y = y2 - 20*vector_y + 5*vector_x; /* Draw second point */ GFillRectangle(diagram, CGM_XOR, x2-3, y2-3, 7, 7); GFillPolygon(diagram, CGM_XOR, vert, 3); GDrawLine(diagram, CGM_XOR, x1, y1, x2 - 20*vector_x, y2 - 20*vector_y); } } string= diagram->labelproc (location); if (string!= NULL && *string!= '\0') GDrawString(diagram, CGM_XOR, vdc2x_x(location->x1, diagram) + 8, vdc2x_y(location->y1 - 3, diagram), string); } void draw_box (int x1, int y1, int x2, int y2, anat_dia *diagram) { int m; if (x2< x1) {m= x1; x1= x2; x2= m;} if (y2< y1) {m= y1; y1= y2; y2= m;} GDrawRectangle(diagram, CGM_XOR, x1, y1, x2- x1, y2- y1); }