1 //      Vector plotting routines.
2 //
3 // Copyright (C) 2004  Andrew Ross
4 //
5 // This file is part of PLplot.
6 //
7 // PLplot is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU Library General Public License as published
9 // by the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // PLplot is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with PLplot; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 
22 #define NEED_PLDEBUG
23 #include "plplotP.h"
24 #include <float.h>
25 #include <ctype.h>
26 
27 // Static function prototypes
28 
29 static void plP_plotvect( PLFLT x, PLFLT y, PLFLT u, PLFLT v, PLFLT scale );
30 
31 //--------------------------------------------------------------------------
32 // N.B. This routine only needed by the Fortran interface to distinguish
33 // the case where both arrowx and arrowy are NULL.  So don't put declaration in
34 // header which might encourage others to use this in some other context.
35 //--------------------------------------------------------------------------
36 PLDLLIMPEXP void
plsvect_null(void)37 plsvect_null( void )
38 {
39     c_plsvect( NULL, NULL, 0, 0 );
40 }
41 
42 //--------------------------------------------------------------------------
43 // void c_plsvect()
44 //
45 // Set the style of the arrow used by plvect
46 //--------------------------------------------------------------------------
47 
48 void
c_plsvect(PLFLT_VECTOR arrowx,PLFLT_VECTOR arrowy,PLINT npts,PLBOOL fill)49 c_plsvect( PLFLT_VECTOR arrowx, PLFLT_VECTOR arrowy, PLINT npts, PLBOOL fill )
50 {
51     int   i;
52     PLFLT def_arrow_x[6] = { -0.5, 0.5, 0.3, 0.5, 0.3, 0.5 };
53     PLFLT def_arrow_y[6] = { 0.0, 0.0, 0.2, 0.0, -0.2, 0.0 };
54 
55     if ( plsc->arrow_x )
56         free_mem( plsc->arrow_x );
57     if ( plsc->arrow_y )
58         free_mem( plsc->arrow_y );
59 
60     // Reset default arrow if null pointers are passed.
61     if ( arrowx == NULL && arrowy == NULL )
62     {
63         arrowx = def_arrow_x;
64         arrowy = def_arrow_y;
65         npts   = 6;
66         fill   = 0;
67     }
68 
69     if ( ( ( plsc->arrow_x = (PLFLT *) malloc( (size_t) npts * sizeof ( PLFLT ) ) ) == NULL ) ||
70          ( ( plsc->arrow_y = (PLFLT *) malloc( (size_t) npts * sizeof ( PLFLT ) ) ) == NULL ) )
71     {
72         plexit( "c_plsvect: Insufficient memory" );
73     }
74 
75     plsc->arrow_npts = npts;
76     plsc->arrow_fill = fill;
77     for ( i = 0; i < npts; i++ )
78     {
79         plsc->arrow_x[i] = arrowx[i];
80         plsc->arrow_y[i] = arrowy[i];
81     }
82 }
83 
84 //
85 // Plot an individual vector
86 //
87 static void
plP_plotvect(PLFLT x,PLFLT y,PLFLT u,PLFLT v,PLFLT scale)88 plP_plotvect( PLFLT x, PLFLT y, PLFLT u, PLFLT v, PLFLT scale )
89 {
90     PLFLT uu, vv, px0, py0, dpx, dpy;
91     PLFLT xt, yt;
92     // Unnecessarily initialize a_y to quiet a -O1 -Wuninitialized warning
93     // which is a false alarm.  (If something goes wrong with the
94     // a_x malloc below any further use of a_y does not occur.)
95     PLINT *a_x, *a_y = NULL;
96     int   j;
97 
98     uu = scale * u;
99     vv = scale * v;
100 
101     if ( uu == 0.0 && vv == 0.0 )
102         return;
103 
104     if ( ( ( a_x = (PLINT *) malloc( sizeof ( PLINT ) * (size_t) ( plsc->arrow_npts ) ) ) == NULL ) ||
105          ( ( a_y = (PLINT *) malloc( sizeof ( PLINT ) * (size_t) ( plsc->arrow_npts ) ) ) == NULL ) )
106     {
107         plexit( "plP_plotvect: Insufficient memory" );
108     }
109 
110     TRANSFORM( x, y, &xt, &yt );
111     px0 = plP_wcpcx( xt );
112     py0 = plP_wcpcy( yt );
113 
114     pldebug( "plP_plotvect", "%f %f %d %d\n", x, y, px0, py0 );
115 
116     TRANSFORM( x + 0.5 * uu, y + 0.5 * vv, &xt, &yt );
117     //printf("plvect: %f %f %f %f %f %f %f\n",scale, x,0.5*uu, y,0.5*vv, xt, yt);
118     dpx = plP_wcpcx( xt ) - px0;
119     dpy = plP_wcpcy( yt ) - py0;
120 
121     // transform arrow -> a
122 
123     for ( j = 0; j < plsc->arrow_npts; j++ )
124     {
125         a_x[j] = (PLINT) ( plsc->arrow_x[j] * dpx - plsc->arrow_y[j] * dpy + px0 );
126         a_y[j] = (PLINT) ( plsc->arrow_x[j] * dpy + plsc->arrow_y[j] * dpx + py0 );
127     }
128 
129     // draw the arrow
130     plP_draphy_poly( a_x, a_y, plsc->arrow_npts );
131     if ( plsc->arrow_fill )
132     {
133         plP_plfclp( a_x, a_y, plsc->arrow_npts, plsc->clpxmi, plsc->clpxma,
134             plsc->clpymi, plsc->clpyma, plP_fill );
135     }
136 
137     free( (void *) a_x );
138     free( (void *) a_y );
139 }
140 
141 //
142 // void plfvect()
143 //
144 // Routine to plot a vector array with arbitrary coordinate
145 // and vector transformations
146 //
plfvect(PLF2EVAL_callback getuv,PLPointer up,PLPointer vp,PLINT nx,PLINT ny,PLFLT scale,PLTRANSFORM_callback pltr,PLPointer pltr_data)147 void plfvect( PLF2EVAL_callback getuv, PLPointer up, PLPointer vp,
148               PLINT nx, PLINT ny, PLFLT scale,
149               PLTRANSFORM_callback pltr, PLPointer pltr_data )
150 {
151     PLINT i, j, i1, j1;
152     PLFLT **u, **v, **x, **y;
153     PLFLT lscale, dx, dy, dxmin, dymin, umax, vmax;
154 
155     if ( pltr == NULL )
156     {
157         // If pltr is undefined, abort with an error.
158         plabort( "plfvect: The pltr callback must be defined" );
159         return;
160     }
161 
162     plAlloc2dGrid( &u, nx, ny );
163     plAlloc2dGrid( &v, nx, ny );
164     plAlloc2dGrid( &x, nx, ny );
165     plAlloc2dGrid( &y, nx, ny );
166 
167     for ( j = 0; j < ny; j++ )
168     {
169         for ( i = 0; i < nx; i++ )
170         {
171             u[i][j] = getuv( i, j, up );
172             v[i][j] = getuv( i, j, vp );
173             pltr( (PLFLT) i, (PLFLT) j, &x[i][j], &y[i][j], pltr_data );
174         }
175     }
176 
177     // Calculate apropriate scaling if necessary
178     if ( scale <= 0.0 )
179     {
180         if ( nx <= 1 && ny <= 1 )
181         {
182             fprintf( stderr, "plfvect: not enough points for autoscaling\n" );
183             return;
184         }
185         dxmin = 10E10;
186         dymin = 10E10;
187         for ( j = 0; j < ny; j++ )
188         {
189             for ( i = 0; i < nx; i++ )
190             {
191                 for ( j1 = j; j1 < ny; j1++ )
192                 {
193                     for ( i1 = 0; i1 < nx; i1++ )
194                     {
195                         dx = fabs( x[i1][j1] - x[i][j] );
196                         dy = fabs( y[i1][j1] - y[i][j] );
197                         if ( dx > 0 )
198                         {
199                             dxmin = ( dx < dxmin ) ? dx : dxmin;
200                         }
201                         if ( dy > 0 )
202                         {
203                             dymin = ( dy < dymin ) ? dy : dymin;
204                         }
205                     }
206                 }
207             }
208         }
209         umax = u[0][0];
210         vmax = v[0][0];
211         for ( j = 0; j < ny; j++ )
212         {
213             for ( i = 0; i < nx; i++ )
214             {
215                 umax = ( u[i][j] > umax ) ? u[i][j] : umax;
216                 vmax = ( v[i][j] > vmax ) ? v[i][j] : vmax;
217             }
218         }
219         if ( umax != 0.0 )
220         {
221             dxmin = dxmin / umax;
222         }
223         else
224         {
225             dxmin = 10E10;
226         }
227         if ( vmax != 0.0 )
228         {
229             dymin = dymin / vmax;
230         }
231         else
232         {
233             dymin = 10E10;
234         }
235         lscale = 1.5 * MIN( dxmin, dymin );
236         if ( scale < 0.0 )
237         {
238             scale = -scale * lscale;
239         }
240         else
241         {
242             scale = lscale;
243         }
244     }
245 
246     for ( j = 0; j < ny; j++ )
247     {
248         for ( i = 0; i < nx; i++ )
249         {
250             plP_plotvect( x[i][j], y[i][j], u[i][j], v[i][j], scale );
251         }
252     }
253 
254     plFree2dGrid( u, nx, ny );
255     plFree2dGrid( v, nx, ny );
256     plFree2dGrid( x, nx, ny );
257     plFree2dGrid( y, nx, ny );
258 }
259 
260 void
c_plvect(PLFLT_MATRIX u,PLFLT_MATRIX v,PLINT nx,PLINT ny,PLFLT scale,PLTRANSFORM_callback pltr,PLPointer pltr_data)261 c_plvect( PLFLT_MATRIX u, PLFLT_MATRIX v, PLINT nx, PLINT ny, PLFLT scale,
262           PLTRANSFORM_callback pltr, PLPointer pltr_data )
263 {
264     plfvect( plf2eval1, (PLPointer) u, (PLPointer) v,
265         nx, ny, scale, pltr, pltr_data );
266 }
267