PLplot: plgradient.c Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plgradient.c
Go to the documentation of this file.
1 // $Id: plgradient.c 12095 2011-12-03 08:56:15Z andrewross $
2 //
3 // Implement linear gradients for PLplot.
4 //
5 // Copyright (C) 2009 Alan W. Irwin
6 //
7 // This file is part of PLplot.
8 //
9 // PLplot is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Library General Public License as published
11 // by the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // PLplot is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU Library General Public License
20 // along with PLplot; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 //
24
25 #include "plplotP.h"
26
27 // To keep track of whether a sofware fallback warning has been issued.
28
29 static int foo;
30 // software fallback for gradient.
31 static void
32 plgradient_soft( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle );
33
34 // define where plshades plots gradient for software fallback for
35 // gradient.
36
37 static PLINT
38 gradient_defined( PLFLT x, PLFLT y );
39
40 //--------------------------------------------------------------------------
41 // void plgradient()
42 //
43 // Draws a linear gradient at an angle relative to the increasing x
44 // direction for the polygon bounded by the x and y vertices. x, and
45 // y are expressed in world coordinates, and angle (in the world
46 // coordinate system) is expressed in degrees. The gradient is
47 // expressed using colour and transparency information from cmap1. The
48 // geometrical gradient direction is specified by the angle argument.
49 // The 0. to 1. range of the independent variable of cmap1 corresponds
50 // to the range of the polygon in the direction specified by angle.
51 //--------------------------------------------------------------------------
52
53 void
54 c_plgradient( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle )
55 {
56 if ( plsc->level < 3 )
57 {
58 plabort( "plgradient: Please set up window first" );
59 return;
60 }
61 if ( n < 3 )
62 {
63 plabort( "plgradient: Not enough vertices in polygon" );
64 return;
65 }
66
67 if ( !plsc->dev_gradient )
68 {
69 if ( !foo )
70 {
71 plwarn( "Driver does not support native gradients, switching to software fallback gradient.\n" );
72 foo = 1;
73 }
74
75 plgradient_soft( n, x, y, angle );
76 }
77 else
78 {
79 #define NGRAD 2
80 int i, irot_min;
81 PLINT _xpoly[PL_MAXPOLY], _ypoly[PL_MAXPOLY];
82 PLINT *xpoly, *ypoly;
83 PLINT xgrad[NGRAD], ygrad[NGRAD], clpxmi, clpxma, clpymi, clpyma;
84 PLFLT dxgrad[NGRAD], dygrad[NGRAD], xrot, xrot_min, xrot_max;
85 PLINT npts;
86
87 // Find (x1, y1) and (x2, y2) corresponding to beginning and end
88 // of gradient vector.
89 double cosangle = cos( PI * angle / 180. );
90 double sinangle = sin( PI * angle / 180. );
91 xrot = x[0] * cosangle + y[0] * sinangle;
92 xrot_min = xrot;
93 xrot_max = xrot;
94 irot_min = 0;
95 for ( i = 1; i < n; i++ )
96 {
97 xrot = x[i] * cosangle + y[i] * sinangle;
98 if ( xrot < xrot_min )
99 {
100 xrot_min = xrot;
101 irot_min = i;
102 }
103 else if ( xrot > xrot_max )
104 {
105 xrot_max = xrot;
106 }
107 }
108 // xrot_min and xrot_max are the minimum and maximum rotated x
109 // coordinate of polygon vertices. Use the vertex corresponding
110 // to the minimum as the (xgrad[0], ygrad[0]) base of the
111 // gradient vector, and calculate the (xgrad[1], ygrad[1]) tip of
112 // the gradient vector from the range in rotated x coordinate and
113 // the angle of the gradient.
114 dxgrad[0] = x[irot_min];
115 dxgrad[1] = dxgrad[0] + ( xrot_max - xrot_min ) * cosangle;
116 dygrad[0] = y[irot_min];
117 dygrad[1] = dygrad[0] + ( xrot_max - xrot_min ) * sinangle;
118 for ( i = 0; i < NGRAD; i++ )
119 {
120 xgrad[i] = plP_wcpcx( dxgrad[i] );
121 ygrad[i] = plP_wcpcy( dygrad[i] );
122 }
123 if ( plsc->difilt )
124 difilt( xgrad, ygrad, NGRAD, &clpxmi, &clpxma, &clpymi, &clpyma );
125 plsc->xgradient = xgrad;
126 plsc->ygradient = ygrad;
127 plsc->ngradient = NGRAD;
128
129 npts = n;
130 if ( n > PL_MAXPOLY - 1 )
131 {
132 xpoly = (PLINT *) malloc( (size_t) ( n + 1 ) * sizeof ( PLINT ) );
133 ypoly = (PLINT *) malloc( (size_t) ( n + 1 ) * sizeof ( PLINT ) );
134
135 if ( ( xpoly == NULL ) || ( ypoly == NULL ) )
136 {
137 plexit( "plgradient: Insufficient memory for large polygon" );
138 }
139 }
140 else
141 {
142 xpoly = _xpoly;
143 ypoly = _ypoly;
144 }
145
146 for ( i = 0; i < n; i++ )
147 {
148 xpoly[i] = plP_wcpcx( x[i] );
149 ypoly[i] = plP_wcpcy( y[i] );
150 }
151 if ( x[0] != x[n - 1] || y[0] != y[n - 1] )
152 {
153 n++;
154 xpoly[n - 1] = plP_wcpcx( x[0] );
155 ypoly[n - 1] = plP_wcpcy( y[0] );
156 }
157 plP_plfclp( xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
158 plsc->clpymi, plsc->clpyma, plP_gradient );
159 // Plot line corresponding to gradient to give visual
160 // debugging cue.
161 //plline( NGRAD, dxgrad, dygrad );
162
163 // Check the original number of points
164 if ( npts > PL_MAXPOLY - 1 )
165 {
166 free( xpoly );
167 free( ypoly );
168 }
169 }
170 }
171
172 //--------------------------------------------------------------------------
173 // void plgradient_soft()
174 //
175 // Software fallback for gradient. See c_plgradient for an explanation
176 // of the arguments.
177 //--------------------------------------------------------------------------
178
179 void
180 plgradient_soft( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle )
181 {
182 PLFLT xrot, xrot_min, xrot_max, cosangle, sinangle;
183 PLFLT xmin, xmax, ymin, ymax;
184 PLFLT **z, *edge, xcoord, ycoord;
185 PLINT i, j;
186
187 if ( n < 3 )
188 {
189 plabort( "plgradient_soft: Not enough vertices in polygon" );
190 return;
191 }
192
193
194 // Define polygon boundary so it is accessible from gradient_defined.
195 plsc->n_polygon = n;
196 plsc->x_polygon = x;
197 plsc->y_polygon = y;
198
199 // Find x and y range of polygon.
200 xmin = x[0];
201 xmax = xmin;
202 ymin = y[0];
203 ymax = ymin;
204 // Also find x range in rotated coordinate system where
205 // xrot = x*cosangle + y*sinangle.
206 cosangle = cos( PI / 180. * angle );
207 sinangle = sin( PI / 180. * angle );
208 xrot = x[0] * cosangle + y[0] * sinangle;
209 xrot_min = xrot;
210 xrot_max = xrot;
211 for ( i = 1; i < n; i++ )
212 {
213 if ( x[i] < xmin )
214 xmin = x[i];
215 else if ( x[i] > xmax )
216 xmax = x[i];
217
218 if ( y[i] < ymin )
219 ymin = y[i];
220 else if ( y[i] > ymax )
221 ymax = y[i];
222
223 xrot = x[i] * cosangle + y[i] * sinangle;
224 if ( xrot < xrot_min )
225 xrot_min = xrot;
226 else if ( xrot > xrot_max )
227 xrot_max = xrot;
228 }
229
230 // 2 x 2 array more than sufficient to define plane.
231 // Temporarily use more to overcome irregular edge issue on defined
232 // region.
233 #define NX 20
234 #define NY 20
235 plAlloc2dGrid( &z, NX, NY );
236 for ( i = 0; i < NX; i++ )
237 {
238 xcoord = xmin + ( (PLFLT) i ) * ( xmax - xmin ) / (PLFLT) ( NX - 1 );
239 for ( j = 0; j < NY; j++ )
240 {
241 ycoord = ymin + ( (PLFLT) j ) * ( ymax - ymin ) / (PLFLT) ( NY - 1 );
242 xrot = xcoord * cosangle + ycoord * sinangle;
243 z[i][j] = ( xrot - xrot_min ) / ( xrot_max - xrot_min );
244 }
245 }
246 // 101 edges gives reasonably smooth results for example 30.
247 #define NEDGE 101
248 // Define NEDGE shade edges (or NEDGE-1 shade levels)
249 // from 0. to 1.
250 if ( ( edge = (PLFLT *) malloc( NEDGE * sizeof ( PLFLT ) ) ) == NULL )
251 plexit( "plgradient_soft: Insufficient memory for large polygon"
252 );
253 for ( i = 0; i < NEDGE; i++ )
254 edge[i] = (PLFLT) i / (PLFLT) ( NEDGE - 1 );
255
256 plshades( (const PLFLT * const *) z, NX, NY, gradient_defined, xmin, xmax, ymin, ymax,
257 edge, NEDGE, 0, 0, 0, plfill, 1, NULL, NULL );
258 free( (void *) edge );
259 plFree2dGrid( z, NX, NY );
260 }
261
262 static PLINT
263 gradient_defined( PLFLT x, PLFLT y )
264 {
265 return plP_pointinpolygon( plsc->n_polygon, plsc->x_polygon, plsc->y_polygon,
266 x, y );
267 }