PLplot: plgradient.c Source File

PLplot 5.15.0

plgradient.c
Go to the documentation of this file.
1 // Implement linear gradients for PLplot.
2 //
3 // Copyright (C) 2009-2014 Alan W. Irwin
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
23 #include "plplotP.h"
24
25 // To keep track of whether a sofware fallback warning has been issued.
26
27 static int foo;
28 // software fallback for gradient.
29 static void
30 plgradient_soft( PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT angle );
31
32 // define where plshades plots gradient for software fallback for
33 // gradient.
34
35 static PLINT
36 gradient_defined( PLFLT x, PLFLT y );
37
38 //--------------------------------------------------------------------------
39 // void plgradient()
40 //
41 // Draws a linear gradient at an angle relative to the increasing x
42 // direction for the polygon bounded by the x and y vertices. x, and
43 // y are expressed in world coordinates, and angle (in the world
44 // coordinate system) is expressed in degrees. The gradient is
45 // expressed using colour and transparency information from cmap1. The
46 // geometrical gradient direction is specified by the angle argument.
47 // The 0. to 1. range of the independent variable of cmap1 corresponds
48 // to the range of the polygon in the direction specified by angle.
49 //--------------------------------------------------------------------------
50
51 void
52 c_plgradient( PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT angle )
53 {
54 if ( plsc->level < 3 )
55 {
56 plabort( "plgradient: Please set up window first" );
57 return;
58 }
59 if ( n < 3 )
60 {
61 plabort( "plgradient: Not enough vertices in polygon" );
62 return;
63 }
64
65 if ( !plsc->dev_gradient )
66 {
67 if ( !foo )
68 {
69 plwarn( "Driver does not support native gradients, switching to software fallback gradient.\n" );
70 foo = 1;
71 }
72
73 plgradient_soft( n, x, y, angle );
74 }
75 else
76 {
77 #define NGRAD 2
78 int i, irot_min;
79 PLINT _xpoly[PL_MAXPOLY], _ypoly[PL_MAXPOLY];
80 PLINT *xpoly, *ypoly;
81 PLINT xgrad[NGRAD], ygrad[NGRAD], clpxmi, clpxma, clpymi, clpyma;
82 PLFLT dxgrad[NGRAD], dygrad[NGRAD], xrot, xrot_min, xrot_max;
83 PLINT npts;
84
85 // Find (x1, y1) and (x2, y2) corresponding to beginning and end
86 // of gradient vector.
87 double cosangle = cos( PI * angle / 180. );
88 double sinangle = sin( PI * angle / 180. );
89 xrot = x[0] * cosangle + y[0] * sinangle;
90 xrot_min = xrot;
91 xrot_max = xrot;
92 irot_min = 0;
93 for ( i = 1; i < n; i++ )
94 {
95 xrot = x[i] * cosangle + y[i] * sinangle;
96 if ( xrot < xrot_min )
97 {
98 xrot_min = xrot;
99 irot_min = i;
100 }
101 else if ( xrot > xrot_max )
102 {
103 xrot_max = xrot;
104 }
105 }
106 // xrot_min and xrot_max are the minimum and maximum rotated x
107 // coordinate of polygon vertices. Use the vertex corresponding
108 // to the minimum as the (xgrad[0], ygrad[0]) base of the
109 // gradient vector, and calculate the (xgrad[1], ygrad[1]) tip of
110 // the gradient vector from the range in rotated x coordinate and
111 // the angle of the gradient.
112 dxgrad[0] = x[irot_min];
113 dxgrad[1] = dxgrad[0] + ( xrot_max - xrot_min ) * cosangle;
114 dygrad[0] = y[irot_min];
115 dygrad[1] = dygrad[0] + ( xrot_max - xrot_min ) * sinangle;
116 for ( i = 0; i < NGRAD; i++ )
117 {
118 xgrad[i] = plP_wcpcx( dxgrad[i] );
119 ygrad[i] = plP_wcpcy( dygrad[i] );
120 }
121 if ( plsc->difilt )
122 difilt( xgrad, ygrad, NGRAD, &clpxmi, &clpxma, &clpymi, &clpyma );
123 plsc->xgradient = xgrad;
124 plsc->ygradient = ygrad;
125 plsc->ngradient = NGRAD;
126
127 npts = n;
128 if ( n > PL_MAXPOLY - 1 )
129 {
130 xpoly = (PLINT *) malloc( (size_t) ( n + 1 ) * sizeof ( PLINT ) );
131 ypoly = (PLINT *) malloc( (size_t) ( n + 1 ) * sizeof ( PLINT ) );
132
133 if ( ( xpoly == NULL ) || ( ypoly == NULL ) )
134 {
135 plexit( "plgradient: Insufficient memory for large polygon" );
136 }
137 }
138 else
139 {
140 xpoly = _xpoly;
141 ypoly = _ypoly;
142 }
143
144 for ( i = 0; i < n; i++ )
145 {
146 xpoly[i] = plP_wcpcx( x[i] );
147 ypoly[i] = plP_wcpcy( y[i] );
148 }
149 if ( x[0] != x[n - 1] || y[0] != y[n - 1] )
150 {
151 n++;
152 xpoly[n - 1] = plP_wcpcx( x[0] );
153 ypoly[n - 1] = plP_wcpcy( y[0] );
154 }
155 plP_plfclp( xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
156 plsc->clpymi, plsc->clpyma, plP_gradient );
157 // Plot line corresponding to gradient to give visual
158 // debugging cue.
159 //plline( NGRAD, dxgrad, dygrad );
160
161 // Check the original number of points
162 if ( npts > PL_MAXPOLY - 1 )
163 {
164 free( xpoly );
165 free( ypoly );
166 }
167 }
168 }
169
170 //--------------------------------------------------------------------------
171 // void plgradient_soft()
172 //
173 // Software fallback for gradient. See c_plgradient for an explanation
174 // of the arguments.
175 //--------------------------------------------------------------------------
176
177 void
178 plgradient_soft( PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT angle )
179 {
180 PLFLT xrot, xrot_min, xrot_max, cosangle, sinangle;
181 PLFLT xmin, xmax, ymin, ymax;
182 PLFLT **z, *edge, xcoord, ycoord;
183 PLINT i, j;
184
185 if ( n < 3 )
186 {
187 plabort( "plgradient_soft: Not enough vertices in polygon" );
188 return;
189 }
190
191
192 // Define polygon boundary so it is accessible from gradient_defined.
193 plsc->n_polygon = n;
194 plsc->x_polygon = x;
195 plsc->y_polygon = y;
196
197 // Find x and y range of polygon.
198 xmin = x[0];
199 xmax = xmin;
200 ymin = y[0];
201 ymax = ymin;
202 // Also find x range in rotated coordinate system where
203 // xrot = x*cosangle + y*sinangle.
204 cosangle = cos( PI / 180. * angle );
205 sinangle = sin( PI / 180. * angle );
206 xrot = x[0] * cosangle + y[0] * sinangle;
207 xrot_min = xrot;
208 xrot_max = xrot;
209 for ( i = 1; i < n; i++ )
210 {
211 if ( x[i] < xmin )
212 xmin = x[i];
213 else if ( x[i] > xmax )
214 xmax = x[i];
215
216 if ( y[i] < ymin )
217 ymin = y[i];
218 else if ( y[i] > ymax )
219 ymax = y[i];
220
221 xrot = x[i] * cosangle + y[i] * sinangle;
222 if ( xrot < xrot_min )
223 xrot_min = xrot;
224 else if ( xrot > xrot_max )
225 xrot_max = xrot;
226 }
227
228 // 2 x 2 array more than sufficient to define plane.
229 // Temporarily use more to overcome irregular edge issue on defined
230 // region.
231 #define NX 20
232 #define NY 20
233 plAlloc2dGrid( &z, NX, NY );
234 for ( i = 0; i < NX; i++ )
235 {
236 xcoord = xmin + ( (PLFLT) i ) * ( xmax - xmin ) / (PLFLT) ( NX - 1 );
237 for ( j = 0; j < NY; j++ )
238 {
239 ycoord = ymin + ( (PLFLT) j ) * ( ymax - ymin ) / (PLFLT) ( NY - 1 );
240 xrot = xcoord * cosangle + ycoord * sinangle;
241 z[i][j] = ( xrot - xrot_min ) / ( xrot_max - xrot_min );
242 }
243 }
244 // 101 edges gives reasonably smooth results for example 30.
245 #define NEDGE 101
246 // Define NEDGE shade edges (or NEDGE-1 shade levels)
247 // from 0. to 1.
248 if ( ( edge = (PLFLT *) malloc( NEDGE * sizeof ( PLFLT ) ) ) == NULL )
249 plexit( "plgradient_soft: Insufficient memory for large polygon"
250 );
251 for ( i = 0; i < NEDGE; i++ )
252 edge[i] = (PLFLT) i / (PLFLT) ( NEDGE - 1 );
253
254 plshades( (PLFLT_MATRIX) z, NX, NY, gradient_defined, xmin, xmax, ymin, ymax,
255 edge, NEDGE, 0, 0, 0, plfill, 1, NULL, NULL );
256 free( (void *) edge );
257 plFree2dGrid( z, NX, NY );
258 }
259
260 static PLINT
261 gradient_defined( PLFLT x, PLFLT y )
262 {
263 return plP_pointinpolygon( plsc->n_polygon, plsc->x_polygon, plsc->y_polygon,
264 x, y );
265 }
plplotP.h
foo
static int foo
Definition: plgradient.c:27
NGRAD
#define NGRAD
plexit
void plexit(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1958
gradient_defined
static PLINT gradient_defined(PLFLT x, PLFLT y)
Definition: plgradient.c:261
plP_wcpcx
PLINT plP_wcpcx(PLFLT x)
Definition: plcvt.c:63
PLFLT_MATRIX
const PLFLT *const * PLFLT_MATRIX
Definition: plplot.h:253
plfill
#define plfill
Definition: plplot.h:717
NEDGE
#define NEDGE
plabort
void plabort(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1894
PLINT
int PLINT
Definition: plplot.h:181
plshades
#define plshades
Definition: plplot.h:824
plFree2dGrid
void plFree2dGrid(PLFLT **f, PLINT nx, PLINT PL_UNUSED(ny))
Definition: plmem.c:116
difilt
void difilt(PLINT *xsc, PLINT *ysc, PLINT npts, PLINT *clpxmi, PLINT *clpxma, PLINT *clpymi, PLINT *clpyma)
Definition: plcore.c:1460
NX
#define NX
c_plgradient
void c_plgradient(PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT angle)
Definition: plgradient.c:52
PLFLT
float PLFLT
Definition: plplot.h:163
plP_gradient
void plP_gradient(short *x, short *y, PLINT npts)
Definition: plcore.c:516
plAlloc2dGrid
void plAlloc2dGrid(PLFLT ***f, PLINT nx, PLINT ny)
Definition: plmem.c:91
plP_plfclp
void plP_plfclp(PLINT *x, PLINT *y, PLINT npts, PLINT xmin, PLINT xmax, PLINT ymin, PLINT ymax, void(*draw)(short *, short *, PLINT))
Definition: plfill.c:538
PI
#define PI
Definition: plplotP.h:290
plP_wcpcy
PLINT plP_wcpcy(PLFLT y)
Definition: plcvt.c:73
plP_pointinpolygon
int plP_pointinpolygon(PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT xp, PLFLT yp)
Definition: plfill.c:1212
plwarn
void plwarn(PLCHAR_VECTOR errormsg)
Definition: plctrl.c:1863
plgradient_soft
static void plgradient_soft(PLINT n, PLFLT_VECTOR x, PLFLT_VECTOR y, PLFLT angle)
Definition: plgradient.c:178
NY
#define NY
PLFLT_VECTOR
const PLFLT * PLFLT_VECTOR
Definition: plplot.h:244
PL_MAXPOLY
#define PL_MAXPOLY
Definition: plplotP.h:283