1 #define MAIN_COXPLOT_FILE
2 #include "coxplot.h"
3 
4 /*****************************************************************************
5   This software is copyrighted and owned by the Medical College of Wisconsin.
6   See the file README.Copyright for details.
7 ******************************************************************************/
8 
9 static int             num_plotar  = 0 ;
10 static MEM_plotdata ** plotar      = NULL ;
11 static int             active_plot = -1 ;
12 
13 static float           active_color = (float) RGB_TO_COL(1.0,1.0,1.0) ;
14 static float           active_thick = 0.0 ;
15 
16 static float           active_opacity = 1.0 ;   /* 22 Jul 2004 */
17 
18 #undef  STATUS
19 #define STATUS(str) fprintf(stderr,"** " str "\n")
20 
21 /*------------------------------------------------------------------------
22    Function to return a pointer to an in-memory plot with the given
23    ident.  A NULL return value indicates failure.
24    A NULL input string will return the current "active" plot.
25 --------------------------------------------------------------------------*/
26 
find_memplot(char * id)27 MEM_plotdata * find_memplot( char * id )
28 {
29    int ip ;
30 
31    if( num_plotar == 0 || plotar == NULL ) return NULL ;
32 
33    if( id == NULL || id[0] == '\0' ){
34       if( active_plot < 0 || active_plot >= num_plotar ) return NULL ;
35       return plotar[active_plot] ;
36    }
37 
38    for( ip=0 ; ip < num_plotar ; ip++ )
39       if( strcmp(plotar[ip]->ident,id) == 0 ) return plotar[ip] ;
40 
41    return NULL ;
42 }
43 
44 /*------------------------------------------------------------------------
45   Function to create an in-memory plot with the given ident and aspect
46   ratio (length of x / length of y).  Also sets the "active" plot to be
47   this new one.  Nonzero return value indicates an error.
48 --------------------------------------------------------------------------*/
49 
create_memplot(char * id,float aspect)50 int create_memplot( char * id , float aspect )
51 {
52    MEM_plotdata * pd ;
53    static int plotpak_framed = 0 ;
54    real asp ;
55 
56    if( find_memplot(id) != NULL ) return 1 ;
57 
58    INIT_MEMPLOT(pd,id) ;
59 
60    if( plotar == NULL ){
61       plotar     = (MEM_plotdata **) malloc( sizeof(MEM_plotdata *) ) ;
62       num_plotar = 0 ;
63    } else {
64       plotar = (MEM_plotdata **)
65                   realloc( plotar , sizeof(MEM_plotdata *)*(num_plotar+1) ) ;
66    }
67 
68    active_plot = num_plotar ;
69    plotar[num_plotar++] = pd ;
70 
71    ADDTO_MEMPLOT( pd , 1.0,0.0,0.0,0.0 , 0.0 , -THCODE_OPAC ) ;  /* 22 Jul 2004 */
72 
73    if( aspect <= 0.0 ) aspect = 1.3 ;
74    asp        = aspect ;
75    pd->aspect = aspect ;
76    memplt_( &asp ) ;                  /* setup PLOTPAK */
77 
78    return 0 ;
79 }
80 
81 /*------------------------------------------------------------------
82    20 Sep 2001: make a plot, fer shur
83 --------------------------------------------------------------------*/
84 
create_memplot_surely(char * id,float aspect)85 int create_memplot_surely( char *id , float aspect )
86 {
87    int ii , jj ;
88    char str[256] ;
89 
90    if( aspect <= 0.0 ) aspect = 1.0 ;  /* backup for stupid users */
91 
92    if( id != NULL && id[0] != '\0'){
93       ii = create_memplot(id,aspect) ;
94       if( ii == 0 ) return 0 ;
95    } else {
96       id = "ElvisWalksTheEarth" ;
97    }
98 
99    for( jj=0 ; ; jj++ ){
100       sprintf(str,"%.240s_%d",id,jj) ;
101       ii = create_memplot(str,aspect) ;
102       if( ii == 0 ) return 0 ;
103    }
104 
105    return 1 ; /* actually, unreachable */
106 }
107 
108 /*-------------------------------------------------------------------------
109    Function to set the "active" plot to a given ident.
110    A nonzero return value indicates an error.
111 ---------------------------------------------------------------------------*/
112 
set_active_memplot(char * id)113 int set_active_memplot( char * id )
114 {
115    int ip ;
116 
117    if( id == NULL || id[0] == '\0' || num_plotar == 0 || plotar == NULL )
118       return 1 ;
119 
120    for( ip=0 ; ip < num_plotar ; ip++ )
121       if( strcmp(plotar[ip]->ident,id) == 0 ){
122          real asp = plotar[ip]->aspect ;
123          active_plot = ip ;
124          memplt_( &asp ) ;    /* re-setup PLOTPAK */
125          return 0 ;
126       }
127 
128    return 1 ;
129 }
130 
get_active_memplot(void)131 MEM_plotdata * get_active_memplot(void)
132 {
133    return find_memplot(NULL) ;
134 }
135 
nline_active_memplot(void)136 int nline_active_memplot(void)
137 {
138    MEM_plotdata * mp ;
139    mp = find_memplot(NULL) ;
140    if( mp == NULL ) return 0 ;
141    return MEMPLOT_NLINE(mp) ;
142 }
143 
144 /*-------------------------------------------------------------------------
145   Functions to set line thickness and color.
146   Color is given as an RGB triple from [0,1] x [0,1] x [0,1].
147   Thickness is given in the same units as coordinates; zero means thin.
148 ---------------------------------------------------------------------------*/
149 
set_color_memplot(float r,float g,float b)150 void set_color_memplot( float r , float g , float b )
151 {
152    if( r > 1.0 || g > 1.0 || b > 1.0 ){        /* 22 Mar 2002:     */
153       r /= 255.0 ; g /= 255.0 ; b /= 255.0 ;   /* allow for 0..255 */
154    }
155    if( r < 0.0 ) r = 0.0 ; else if ( r > 1.0 ) r = 1.0 ;
156    if( g < 0.0 ) g = 0.0 ; else if ( g > 1.0 ) g = 1.0 ;
157    if( b < 0.0 ) b = 0.0 ; else if ( b > 1.0 ) b = 1.0 ;
158 
159    active_color = (float) RGB_TO_COL(r,g,b) ;
160    return ;
161 }
162 
163 /*----- This routine is called from color.f -----*/
164 
zzmpco_(float * r,float * g,float * b)165 void zzmpco_( float * r , float * g , float * b )
166 {
167    set_color_memplot( *r , *g , *b ) ;
168    return ;
169 }
170 
set_thick_memplot(float th)171 void set_thick_memplot( float th )
172 {
173    if( th < 0.0 ) th = 0.0 ;
174    active_thick = th ;
175    return ;
176 }
177 
get_thick_memplot(void)178 float get_thick_memplot( void )
179 {
180    return active_thick ;
181 }
182 
set_opacity_memplot(float th)183 void set_opacity_memplot( float th )  /* 22 Jul 2004 */
184 {
185    MEM_plotdata *mp ;
186 
187         if( th < 0.0 ) th = 0.0 ;
188    else if( th > 1.0 ) th = 1.0 ;
189    active_opacity = th ;
190 
191    /* Set opacity for further drawing [22 Jul 2004] */
192 
193    if( active_plot < 0 || active_plot >= num_plotar ||
194        num_plotar == 0 || plotar == NULL            ||
195        plotar[active_plot] == NULL                    ) return ;
196 
197    mp = plotar[active_plot] ;
198    ADDTO_MEMPLOT( mp , th,0.0,0.0,0.0 , 0.0 , -THCODE_OPAC ) ;
199    return ;
200 }
201 
get_opacity_memplot(void)202 float get_opacity_memplot( void )
203 {
204    return active_opacity ;
205 }
206 
207 /*------------------------------------------------------------------
208   where the actual plotting into the memplot is done from
209   the coxplot functions
210 --------------------------------------------------------------------*/
211 
plotline_memplot(float x1,float y1,float x2,float y2)212 void plotline_memplot( float x1 , float y1 , float x2 , float y2 )
213 {
214    MEM_plotdata * mp ;
215 
216    if( active_plot < 0 || active_plot >= num_plotar ||
217        num_plotar == 0 || plotar == NULL            ||
218        plotar[active_plot] == NULL                    ) return ;
219 
220    mp = plotar[active_plot] ;
221 
222 #if 0
223 fprintf(stderr,"** plotline_memplot %d: (%f,%f) to (%f,%f)\n",
224         MEMPLOT_NLINE(mp) , x1,y1,x2,y2) ;
225 #endif
226 
227    ADDTO_MEMPLOT( mp , x1,y1,x2,y2 , active_color , active_thick ) ;
228    return ;
229 }
230 
plotrect_memplot(float x1,float y1,float x2,float y2)231 void plotrect_memplot( float x1 , float y1 , float x2 , float y2 ) /* 21 Mar 2001 */
232 {
233    MEM_plotdata * mp ;
234 
235    if( active_plot < 0 || active_plot >= num_plotar ||
236        num_plotar == 0 || plotar == NULL            ||
237        plotar[active_plot] == NULL                    ) return ;
238 
239    mp = plotar[active_plot] ;
240 
241    ADDTO_MEMPLOT( mp , x1,y1,x2,y2 , active_color , -THCODE_RECT ) ;
242    return ;
243 }
244 
plotfrect_memplot(float x1,float y1,float x2,float y2)245 void plotfrect_memplot( float x1 , float y1 , float x2 , float y2 ) /* 24 Apr 2012 */
246 {
247    MEM_plotdata * mp ;
248 
249    if( active_plot < 0 || active_plot >= num_plotar ||
250        num_plotar == 0 || plotar == NULL            ||
251        plotar[active_plot] == NULL                    ) return ;
252 
253    mp = plotar[active_plot] ;
254 
255    ADDTO_MEMPLOT( mp , x1,y1,x2,y2 , active_color , -THCODE_FRECT ) ;
256    return ;
257 }
258 
plotcirc_memplot(float x1,float y1,float rad)259 void plotcirc_memplot( float x1 , float y1 , float rad ) /* 10 Mar 2002 */
260 {
261    MEM_plotdata * mp ;
262 
263    if( active_plot < 0 || active_plot >= num_plotar ||
264        num_plotar == 0 || plotar == NULL            ||
265        plotar[active_plot] == NULL                    ) return ;
266 
267    mp = plotar[active_plot] ;
268 
269    ADDTO_MEMPLOT( mp , x1,y1,rad,0.0 , active_color , -THCODE_CIRC ) ;
270    return ;
271 }
272 
plotball_memplot(float x1,float y1,float rad)273 void plotball_memplot( float x1 , float y1 , float rad )
274 {
275    MEM_plotdata * mp ;
276 
277    if( active_plot < 0 || active_plot >= num_plotar ||
278        num_plotar == 0 || plotar == NULL            ||
279        plotar[active_plot] == NULL                    ) return ;
280 
281    mp = plotar[active_plot] ;
282 
283    ADDTO_MEMPLOT( mp , x1,y1,rad,0.0 , active_color , -THCODE_BALL ) ;
284    return ;
285 }
286 
287 /*----- This routine is called from zzphph.f to draw 1 actual line -----*/
288 
zzmpli_(float * x1,float * y1,float * x2,float * y2)289 void zzmpli_( float * x1 , float * y1 , float * x2 , float * y2 )
290 {
291    plotline_memplot( *x1 , *y1 , *x2 , *y2 ) ;
292    return ;
293 }
294 
295 /*------------------------------------------------------------------------
296    Delete the active in-memory plot.
297    After this, there is no "active" plot.
298 --------------------------------------------------------------------------*/
299 
delete_active_memplot(void)300 void delete_active_memplot(void)
301 {
302    int ip ;
303 
304    if( active_plot < 0 || active_plot >= num_plotar ||
305        num_plotar == 0 || plotar == NULL            ||
306        plotar[active_plot] == NULL                    ) return ;
307 
308    DESTROY_MEMPLOT( plotar[active_plot] ) ;
309 
310    if( num_plotar == 1 ){
311       free(plotar) ; plotar = NULL ; num_plotar = 0 ;
312    } else {
313       for( ip=active_plot+1 ; ip < num_plotar ; ip++ ) plotar[ip-1] = plotar[ip] ;
314       num_plotar-- ; plotar[num_plotar] = NULL ;
315    }
316 
317    active_plot = -1 ;
318    return ;
319 }
320 
321 /*------------------------------------------------------------------------*/
322 
delete_memplot(MEM_plotdata * mp)323 void delete_memplot( MEM_plotdata * mp )
324 {
325    int ip ;
326 
327    if( num_plotar == 0 || plotar == NULL || mp == NULL ) return ;
328 
329    for( ip=0 ; ip < num_plotar ; ip++ ) if( plotar[ip] == mp ) break ;
330 
331    if( ip < num_plotar ){
332            if( active_plot == ip ) active_plot = -1 ;
333       else if( active_plot >  ip ) active_plot-- ;
334 
335       for( ip++ ; ip < num_plotar ; ip++ ) plotar[ip-1] = plotar[ip] ;
336 
337       num_plotar-- ; plotar[num_plotar] = NULL ;
338    }
339 
340    DESTROY_MEMPLOT( mp ) ;
341    return ;
342 }
343 
344 /*-----------------------------------------------------------------------
345    Scale data inside an memplot -- 26 Feb 2001
346       x_new     = sx * x_old + tx
347       y_new     = sy * y_old + ty
348       thick_new = st * thick_old
349 -------------------------------------------------------------------------*/
350 
scale_memplot(float sx,float tx,float sy,float ty,float st,MEM_plotdata * mp)351 void scale_memplot( float sx , float tx ,
352                     float sy , float ty , float st , MEM_plotdata * mp )
353 {
354    int ii,nn ;
355    if( mp == NULL ) return ;
356 
357    for( nn=ii=0 ; ii < mp->nxyline ; ii++ ){
358       if( mp->xyline[nn+5] == -THCODE_OPAC ){  /* 21 Mar 2017 */
359         nn += 6 ;
360       } else {
361         mp->xyline[nn] = mp->xyline[nn] * sx + tx ; nn++ ; /* x1 */
362         mp->xyline[nn] = mp->xyline[nn] * sy + ty ; nn++ ; /* y1 */
363         mp->xyline[nn] = mp->xyline[nn] * sx + tx ; nn++ ; /* x2 */
364         mp->xyline[nn] = mp->xyline[nn] * sy + ty ; nn++ ; /* y2 */
365         /** no change here */                       nn++ ; /* color */
366         if( mp->xyline[nn] > 0.0f )
367           mp->xyline[nn] = mp->xyline[nn] * st    ; nn++ ; /* thick */
368       }
369    }
370    return ;
371 }
372 
373 /*-----------------------------------------------------------------------
374    Append data from one memplot to another -- 26 Feb 2001
375 -------------------------------------------------------------------------*/
376 
append_to_memplot(MEM_plotdata * mp,MEM_plotdata * ap)377 void append_to_memplot( MEM_plotdata * mp , MEM_plotdata * ap )
378 {
379    int nn , nold ;
380    if( mp == NULL || ap == NULL || ap->nxyline <= 0 ) return ;
381 
382    nn = mp->nxyline + ap->nxyline ;
383    mp->xyline = (float *) realloc(mp->xyline,
384                                   sizeof(float)*NXY_MEMPLOT*nn) ;
385 
386    memcpy( mp->xyline + NXY_MEMPLOT*mp->nxyline ,
387            ap->xyline , sizeof(float)*NXY_MEMPLOT*ap->nxyline ) ;
388 
389    mp->nxyline = mp->nxyline_all = nn ;
390    return ;
391 }
392 
393 /*-----------------------------------------------------------------------
394    Make a copy of a memplot; the new one will be the active memplot
395    -- 26 Feb 2001 -- RWCox
396 -------------------------------------------------------------------------*/
397 
copy_memplot(MEM_plotdata * mp)398 MEM_plotdata * copy_memplot( MEM_plotdata * mp )
399 {
400    MEM_plotdata * np ;
401    char str[256] ; int nn ;
402 
403    if( mp == NULL ) return NULL ;
404 
405    /* make a new ID string */
406 
407    for( nn=1 ; nn <= 9999 ; nn++ ){
408       sprintf(str,"%.240sCopy%04d",mp->ident,nn) ;
409       if( find_memplot(str) == NULL ) break ;
410    }
411    if( nn == 1000 ) return NULL ; /* this is bad (but unlikely) */
412 
413    /* make the new memplot */
414 
415    nn = create_memplot( str , mp->aspect ) ;
416    if( nn ) return NULL ;         /* this is real bad */
417 
418    np = find_memplot(NULL) ;      /* is the new one */
419    if( np == NULL ) return NULL ; /* shouldn't happen */
420 
421    /* copy data from old one into new one */
422 
423    nn = np->nxyline = np->nxyline_all = mp->nxyline ;
424    np->xyline = (float *) realloc(np->xyline,
425                                   sizeof(float)*NXY_MEMPLOT*nn) ;
426    memcpy( np->xyline , mp->xyline , sizeof(float)*NXY_MEMPLOT*nn ) ;
427 
428    return np ;
429 }
430 
431 /*----------------------------------------------------------------------
432    Flip a memplot inplace - 30 Aug 2001 - RWCox
433      rot    = one of the MRI_ROT_ codes (see coxplot.h)
434      mirror = whether to left-right mirror after rotation
435 ------------------------------------------------------------------------*/
436 
flip_memplot(int rot,int mirror,MEM_plotdata * mp)437 void flip_memplot( int rot , int mirror , MEM_plotdata *mp )
438 {
439    int fopt , ii,nn ;
440    float xtop , ytop=1.0 , x1,y1,x2,y2 ;
441    int thc ;
442 
443    if( mp == NULL ) return ;                          /* nothing in */
444    if( rot == MRI_ROT_0 && mirror == FALSE ) return ; /* do nothing */
445 
446    xtop = mp->aspect ;
447 
448    fopt = (mirror) ? (rot+MRI_FLMADD) : (rot) ;
449    switch( fopt ){
450 
451       default: return ;  /* should never happen */
452 
453       case MRI_ROT_90:
454        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
455           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
456           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
457           thc = (int)mp->xyline[nn+5] ; if( thc == -THCODE_OPAC ) continue ;
458           mp->xyline[nn  ] = ytop - y1 ;
459           mp->xyline[nn+1] = x1 ;       if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
460           mp->xyline[nn+2] = ytop - y2 ;
461           mp->xyline[nn+3] = x2 ;
462        }
463       break ;
464 
465       case MRI_ROT_180:
466        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
467           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
468           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
469           thc = (int)mp->xyline[nn+5] ;  if( thc == -THCODE_OPAC ) continue ;
470           mp->xyline[nn  ] = xtop - x1 ;
471           mp->xyline[nn+1] = ytop - y1 ; if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
472           mp->xyline[nn+2] = xtop - x2 ;
473           mp->xyline[nn+3] = ytop - y2 ;
474        }
475       break ;
476 
477       case MRI_ROT_270:
478        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
479           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
480           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
481           thc = (int)mp->xyline[nn+5] ;  if( thc == -THCODE_OPAC ) continue ;
482           mp->xyline[nn  ] = y1 ;
483           mp->xyline[nn+1] = xtop - x1 ; if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
484           mp->xyline[nn+2] = y2 ;
485           mp->xyline[nn+3] = xtop - x2 ;
486        }
487       break ;
488 
489       case (MRI_ROT_0+MRI_FLMADD):
490        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
491           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
492           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
493           thc = (int)mp->xyline[nn+5] ; if( thc == -THCODE_OPAC ) continue ;
494           mp->xyline[nn  ] = xtop - x1 ;
495           mp->xyline[nn+1] = y1 ;       if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
496           mp->xyline[nn+2] = xtop - x2 ;
497           mp->xyline[nn+3] = y2 ;
498        }
499       break ;
500 
501       case (MRI_ROT_90+MRI_FLMADD):
502        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
503           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
504           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
505           thc = (int)mp->xyline[nn+5] ; if( thc == -THCODE_OPAC ) continue ;
506           mp->xyline[nn  ] = y1 ;
507           mp->xyline[nn+1] = x1 ;       if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
508           mp->xyline[nn+2] = y2 ;
509           mp->xyline[nn+3] = x2 ;
510        }
511       break ;
512 
513       case (MRI_ROT_180+MRI_FLMADD):
514        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
515           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
516           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
517           thc = (int)mp->xyline[nn+5]  ; if( thc == -THCODE_OPAC ) continue ;
518           mp->xyline[nn  ] = x1 ;
519           mp->xyline[nn+1] = ytop - y1 ; if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
520           mp->xyline[nn+2] = x2 ;
521           mp->xyline[nn+3] = ytop - y2 ;
522        }
523       break ;
524 
525       case (MRI_ROT_270+MRI_FLMADD):
526        for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
527           x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
528           x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
529           thc = (int)mp->xyline[nn+5]  ; if( thc == -THCODE_OPAC ) continue ;
530           mp->xyline[nn  ] = ytop - y1 ;
531           mp->xyline[nn+1] = xtop - x1 ; if( thc == -THCODE_CIRC || thc == -THCODE_BALL ) continue ;
532           mp->xyline[nn+2] = ytop - y2 ;
533           mp->xyline[nn+3] = xtop - x2 ;
534        }
535       break ;
536    }
537 
538    return ;
539 }
540 
541 /*---------------------------------------------------------------------------
542   Set the insertion point for over-writing -- 15 Nov 2001
543 -----------------------------------------------------------------------------*/
544 
insert_at_memplot(int ii,MEM_plotdata * mp)545 void insert_at_memplot( int ii , MEM_plotdata *mp )
546 {
547    if( mp != NULL ) mp->insert_at = ii ;
548    return ;
549 }
550 
551 /*---------------------------------------------------------------------------
552   Cut lines nbot..ntop out of a memplot -- 15 Nov 2001
553 -----------------------------------------------------------------------------*/
554 
cutlines_memplot(int nbot,int ntop,MEM_plotdata * mp)555 void cutlines_memplot( int nbot , int ntop , MEM_plotdata *mp )
556 {
557    if( mp == NULL          ) return ;  /* bad or meaningless stuff */
558    if( nbot <  0           ) return ;
559    if( ntop >= mp->nxyline ) return ;
560    if( nbot > ntop         ) return ;
561 
562    if( ntop == mp->nxyline-1 ){  /* just set num lines to nbot */
563 
564       mp->nxyline = nbot ;
565 
566    } else {                      /* must move things above ntop down */
567 
568       memmove( mp->xyline + NXY_MEMPLOT*nbot ,
569                mp->xyline + NXY_MEMPLOT*(ntop+1) ,
570                sizeof(float)*NXY_MEMPLOT*(mp->nxyline-1-ntop) ) ;
571 
572       mp->nxyline -= (ntop-nbot+1) ;
573 
574    }
575    return ;
576 }
577 
578 /*----------------------------------------------------------------------------*/
579 
580 #undef INLINE
581 #ifdef __GNUC__
582 # define INLINE inline
583 #else
584 # define INLINE /*nada*/
585 #endif
586 
587 /*----------------------------------------------------------------------------
588   Clip a line to a rectangle.  Return is -1 if the line is totally outside.
589   Otherwise, return is 0 and *x1in (etc.) is altered to the clipped line.
590 ------------------------------------------------------------------------------*/
591 
clip_line_to_rect(float xclbot,float yclbot,float xcltop,float ycltop,float * x1in,float * y1in,float * x2in,float * y2in)592 static INLINE int clip_line_to_rect( float xclbot , float yclbot ,
593                                      float xcltop , float ycltop ,
594                                      float *x1in  , float *y1in  ,
595                                      float *x2in  , float *y2in   )
596 {
597    float x1=*x1in , y1=*y1in , x2=*x2in , y2=*y2in , dx,dy,slope,temp ;
598    int inter=0 ;
599 
600    /* Make sure that x1 < x2 by interchanging the points if necessary */
601 
602    if( x1 > x2 ){
603      temp=x1 ; x1=x2 ; x2=temp;
604      temp=y1 ; y1=y2 ; y2=temp; inter=1 ;
605    }
606 
607    /* if outside entire region, throw line away */
608 
609    if( x2 < xclbot || x1 > xcltop ) return -1;
610 
611    if( y1 < y2 ){
612      if( y2 < yclbot || y1 > ycltop ) return -1;
613    } else {
614      if( y1 < yclbot || y2 > ycltop ) return -1;
615    }
616 
617    /* if inside entire region, then do nothing */
618 
619    if( x1 >= xclbot && x2 <= xcltop ){
620      if( y1 < y2 ){
621        if( y1 >= yclbot && y2 <= ycltop ) return 0 ;
622      } else {
623        if( y2 >= yclbot && y1 <= ycltop ) return 0 ;
624      }
625    }
626 
627    /* Clip line in X direction */
628 
629    dx = x2 - x1 ;
630    if( dx > 0.0 ){  /* only clip if line has some x range */
631      slope = (y2-y1)/dx ;
632      if( x1 < xclbot ){  /* intercept of line at left side */
633        y1 = y1 + slope*(xclbot-x1) ;
634        x1 = xclbot ;
635      }
636      if( x2 > xcltop ){  /* intercept at right */
637        y2 = y2 + slope*(xcltop-x2) ;
638        x2 = xcltop ;
639      }
640    }
641 
642    /* Check line again to see if it falls outside of plot region */
643 
644    if( y1 < y2 ){
645      if( y2 < yclbot || y1 > ycltop ) return -1;
646    } else {
647      if( y1 < yclbot || y2 > ycltop ) return -1;
648 
649      temp=x1 ; x1=x2 ; x2=temp;                 /* make sure y1 <= y2 */
650      temp=y1 ; y1=y2 ; y2=temp; inter=!inter ;
651    }
652 
653    /* Clip y-direction.  To do this, must have y1 <= y2 [supra] */
654 
655    dy = y2 - y1 ;
656    if( dy > 0.0 ){  /* only clip if line has some Y range */
657      slope = (x2-x1)/dy ;
658      if( y1 < yclbot ){ /* intercept of line at bottom */
659        x1 = x1 + slope*(yclbot-y1) ;
660        y1 = yclbot ;
661      }
662      if( y2 > ycltop ){ /* intercept at top */
663        x2 = x2 + slope*(ycltop-y2) ;
664        y2 = ycltop ;
665      }
666    }
667 
668    /* Line is now guaranteed to be totally inside the plot region.
669       Copy local clipped coordinates to output values and return.
670       Note that we must restore points to original input order,
671       if they were interchanged at some point above.              */
672 
673    if( inter ){
674      *x1in = x2 ; *x2in = x1 ; *y1in = y2 ; *y2in = y1 ;
675    } else {
676      *x1in = x1 ; *y1in = y1 ; *x2in = x2 ; *y2in = y2 ;
677    }
678 
679    return 0 ;
680 }
681 
682 #undef INSIDE
683 #define INSIDE(x,y)                                                    \
684   ( (x) >= xclbot && (x) <= xcltop && (y) >= yclbot && (y) <= ycltop )
685 
686 /*---------------------------------------------------------------------------
687   Clip a memplot to a rectangle, producing a new memplot.
688 -----------------------------------------------------------------------------*/
689 
clip_memplot(float xclbot,float yclbot,float xcltop,float ycltop,MEM_plotdata * mp)690 MEM_plotdata * clip_memplot( float xclbot, float yclbot,
691                              float xcltop, float ycltop , MEM_plotdata *mp )
692 {
693    MEM_plotdata *np ;
694    char str[256] ;
695    int nn , ii , qq ;
696    float x1,y1 , x2,y2 , col,th ;
697 
698    if( mp == NULL       ) return NULL ;  /* bad or meaningless stuff */
699    if( xclbot >= xcltop ) return NULL ;
700    if( yclbot >= ycltop ) return NULL ;
701 
702    sprintf(str,"%.240sCopy",mp->ident) ;
703    nn = create_memplot_surely( str , mp->aspect ) ;
704    np = find_memplot(NULL) ;
705    if( np == NULL ) return NULL ; /* shouldn't happen */
706 
707    for( nn=ii=0 ; ii < mp->nxyline ; ii++,nn+=NXY_MEMPLOT ){
708      x1 = mp->xyline[nn  ] ; y1 = mp->xyline[nn+1] ;
709      x2 = mp->xyline[nn+2] ; y2 = mp->xyline[nn+3] ;
710      col= mp->xyline[nn+4] ; th = mp->xyline[nn+5] ;
711 
712      if( th < 0.0 ){               /** Not a line! */
713        int thc = (int)(-th) ;
714        switch( thc ){
715          case THCODE_RECT:         /* rectangle */
716                                    /* both corners inside */
717            if( INSIDE(x1,y1) && INSIDE(x2,y2) ){
718              ADDTO_MEMPLOT(np,x1,y1,x2,y2,col,th) ;
719            }
720          break ;
721 
722          case THCODE_BALL:
723          case THCODE_CIRC:{        /* circle */
724                                    /* +/- 1 radius inside */
725            float xx,yy , rr=x2 ;
726            xx = x1+rr ; if( !INSIDE(xx,y1) ) break ;
727            xx = x1-rr ; if( !INSIDE(xx,y1) ) break ;
728            yy = y1+rr ; if( !INSIDE(x1,yy) ) break ;
729            yy = y1-rr ; if( !INSIDE(x1,yy) ) break ;
730            ADDTO_MEMPLOT(np,x1,y1,x2,y2,col,th) ;
731          }
732          break ;
733 
734          case THCODE_OPAC:{
735            ADDTO_MEMPLOT(np,x1,0.0f,0.0f,0.0f,col,th) ;
736          }
737          break ;
738        }
739 
740      } else {                      /** Truly a line! **/
741 
742        qq = clip_line_to_rect( xclbot,yclbot , xcltop,ycltop ,
743                                &x1,&y1       , &x2,&y2        ) ;
744        if( qq == 0 ){
745          ADDTO_MEMPLOT(np,x1,y1,x2,y2,col,th) ;
746        }
747      }
748    }
749 
750    if( np->nxyline == 0 ) DESTROY_MEMPLOT(np) ;
751 
752    return np ;
753 }
754 
755 /****************************************************************************
756   Functions to interface with PLOTPAK Fortran routines
757 *****************************************************************************/
758 
759 /*-------------------------------
760   Has no function at this time.
761 ---------------------------------*/
plotpak_frame(void)762 void plotpak_frame(void) { frame_() ; }
763 
764 /*-----------------------------------------------
765    Draws a sequence of lines in one swell foop.
766 -------------------------------------------------*/
plotpak_curve(float * x,float * y,int n)767 void plotpak_curve( float * x , float * y , int n )
768 {
769    integer nn = n ;
770    curve_( (real *) x , (real *) y , &nn ) ;
771 }
772 
773 /*---------------------------------------------------
774   Establishes first point of a series of lines
775   to be drawn one at time using plotpak_vector.
776 -----------------------------------------------------*/
plotpak_frstpt(float x,float y)777 void plotpak_frstpt( float x , float y )
778 {
779    real xx = x , yy = y ;
780    frstpt_( &xx , &yy ) ;
781 }
782 
783 /*---------------------------------------------------
784   Draws next in the series of lines.
785 -----------------------------------------------------*/
plotpak_vector(float x,float y)786 void plotpak_vector( float x , float y )
787 {
788    real xx=x , yy=y ;
789    vector_( &xx , &yy ) ;
790 }
791 
792 /*-------------------
793    Draws one line.
794 ---------------------*/
plotpak_line(float x1,float y1,float x2,float y2)795 void plotpak_line( float x1 , float y1 , float x2 , float y2 )
796 {
797    real xx1 = x1 , yy1 = y1 , xx2 = x2 , yy2 = y2 ;
798    line_(&xx1, &yy1, &xx2, &yy2);
799 }
800 
801 /*--------------------------------------------------------------
802  Converts (x1,y1) from user to memplot coordinates - 20 Nov 2001
803 ----------------------------------------------------------------*/
804 
plotpak_zzphys(float x1,float y1,float * x2,float * y2)805 void plotpak_zzphys( float x1 , float y1 , float *x2 , float *y2 )
806 {
807    real xx1 = x1 , yy1 = y1 ;
808    zzphys_( &xx1 , &yy1 ) ;
809    if( x2 != NULL ) *x2 = xx1 ;
810    if( y2 != NULL ) *y2 = yy1 ;
811 }
812 
813 /*--------------------------------------------------------------
814  Converts (x1,y1) from memplot to user coordinates - 20 Nov 2001
815 ----------------------------------------------------------------*/
816 
plotpak_unphys(float x1,float y1,float * x2,float * y2)817 void plotpak_unphys( float x1 , float y1 , float *x2 , float *y2 )
818 {
819    double rr ;
820    if( x2 != NULL ){
821       rr = (x1 - zzzplt_.betaxx) / zzzplt_.alphxx ;
822       if( zzzplt_.ixcoor < 0 ) rr = pow(10.0,rr) ;
823       *x2 = rr ;
824    }
825    if( y2 != NULL ){
826       rr = (y1 - zzzplt_.betayy) / zzzplt_.alphyy ;
827       if( zzzplt_.iycoor < 0 ) rr = pow(10.0,rr) ;
828       *y2 = rr ;
829    }
830 }
831 
832 /*-----------------------------------------------------------------------------
833   Establishes relationship between objective (memplot) coordinates
834   (x range is from 0 to aspect, y from 0 to 1.0) and subjective (user)
835   coordinates.  The range xs1..xs2 is mapped onto xo1..xo2, and similarly
836   for y.  "code" establishes the form of the mapping:
837     code = 1 => x linear, y linear
838     code = 2 => x linear, y logarithmic
839     code = 3 => x log   , y linear
840     code = 4 => x log   , y log
841 -------------------------------------------------------------------------------*/
plotpak_set(float xo1,float xo2,float yo1,float yo2,float xs1,float xs2,float ys1,float ys2,int code)842 void plotpak_set( float xo1,float xo2 , float yo1,float yo2 ,
843                   float xs1,float xs2 , float ys1,float ys2 , int code )
844 {
845    real xobj1=xo1, xobj2=xo2, yobj1=yo1, yobj2=yo2;
846    real xsub1=xs1, xsub2=xs2, ysub1=ys1, ysub2=ys2 ;
847    integer ltype = code ;
848    set_(&xobj1, &xobj2, &yobj1, &yobj2, &xsub1, &xsub2, &ysub1, &ysub2, &ltype);
849 }
850 
plotpak_getset(float * xo1,float * xo2,float * yo1,float * yo2,float * xs1,float * xs2,float * ys1,float * ys2)851 void plotpak_getset( float *xo1,float *xo2 , float *yo1,float *yo2 ,
852                      float *xs1,float *xs2 , float *ys1,float *ys2  )
853 {
854    if( xo1 != NULL ) *xo1 = (float) zzzplt_.xbot ;
855    if( xo2 != NULL ) *xo2 = (float) zzzplt_.xtop ;
856    if( yo1 != NULL ) *yo1 = (float) zzzplt_.ybot ;
857    if( yo1 != NULL ) *yo2 = (float) zzzplt_.ytop ;
858 
859    if( xs1 != NULL ) *xs1 = (float) zzzplt_.xmin ;
860    if( xs2 != NULL ) *xs2 = (float) zzzplt_.xmax ;
861    if( ys1 != NULL ) *ys1 = (float) zzzplt_.ymin ;
862    if( ys1 != NULL ) *ys2 = (float) zzzplt_.ymax ;
863 
864    return ;
865 }
866 
867 /*-----------------------------------------
868   Set line type: 1 = solid (default)
869                  2 = long dash
870                  3 = short dash
871                  4 = long - short - short
872                  5 = very short
873 -------------------------------------------*/
plotpak_setlin(int code)874 void plotpak_setlin( int code )
875 {
876    integer ntype=code ;
877    setlin_(&ntype);
878 }
879 
880 /*------------------------------------------------
881   Set the clipping window (objective coordinates)
882 --------------------------------------------------*/
plotpak_setw(float xo1,float xo2,float yo1,float yo2)883 void plotpak_setw( float xo1,float xo2 , float yo1,float yo2 )
884 {
885    real xobj1=xo1, xobj2=xo2, yobj1=yo1, yobj2=yo2;
886    setw_( &xobj1, &xobj2, &yobj1, &yobj2 ) ;
887 }
888 
889 /*------- Plotpak routines that I'm not documenting yet
890           see the .f source code, or NCAR manual, if you care -------*/
891 
plotpak_setdsh(int nd,float * xd)892 void plotpak_setdsh( int nd , float * xd )
893 {
894    integer nnd = nd ;
895    setdsh_( &nnd , (real *) xd ) ;
896 }
897 
plotpak_setfrm(float xo1,float xo2,float yo1,float yo2)898 void plotpak_setfrm( float xo1,float xo2 , float yo1,float yo2 )
899 {
900    real xobj1=xo1, xobj2=xo2, yobj1=yo1, yobj2=yo2;
901    setfrm_( &xobj1, &xobj2, &yobj1, &yobj2 ) ;
902 }
903 
plotpak_phdot(float x1,float y1)904 void plotpak_phdot( float x1 , float y1 )
905 {
906    real xx1=x1 , yy1=y1 ;
907    phdot_(&xx1,&yy1);
908 }
909 
plotpak_phline(float x1,float y1,float x2,float y2)910 void plotpak_phline( float x1 , float y1 , float x2 , float y2 )
911 {
912    real xx1 = x1 , yy1 = y1 , xx2 = x2 , yy2 = y2 ;
913    phline_(&xx1, &yy1, &xx2, &yy2);
914 }
915 
plotpak_point(float x1,float y1)916 void plotpak_point( float x1 , float y1 )
917 {
918    real xx1=x1 , yy1=y1 ;
919    point_(&xx1,&yy1);
920 }
921 
plotpak_points(float * x,float * y,int n,int ipen)922 void plotpak_points( float *x , float *y , int n , int ipen )
923 {
924    integer nn=n , nipen=ipen , zero=0 ;
925    points_( (real *)x , (real *)y , &nn , &zero , &nipen ) ;
926 }
927 
928 void ppak_garbage_routine(void) ;
this_is_real_junk(void)929 void this_is_real_junk(void){ ppak_garbage_routine(); }
930