1 /*
2
3 Copyright (C) 2008-2021 Michele Martone
4
5 This file is part of librsb.
6
7 librsb is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 librsb is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with librsb; see the file COPYING.
19 If not, see <http://www.gnu.org/licenses/>.
20
21 */
22 /* @cond INNERDOC */
23 /*!
24 * @file
25 * @author Michele Martone
26 * @brief
27 * This source file contains pixmap rendering functions.
28 * */
29 /*
30 * this code is EXPERIMENTAL and UNFINISHED
31 *
32 * TODO : with very little effort, we could introduce
33 * - a mipmap based rsb_mtx_mipmap_t struct
34 * - column major, too
35 * - remove extra headers dumpout
36 * */
37
38 #include "rsb_internals.h" /* rsb_coo_matrix_t */
39
rsb__do_print_postscript_header(FILE * fd,int width,int height,float csw,float csh)40 rsb_err_t rsb__do_print_postscript_header(FILE*fd, int width, int height, float csw, float csh)
41 {
42 /**
43 \ingroup gr_internals
44 Prints an Encapsulated Postscript header for an area originating at (0 0),
45 bound by (width,height), and defining 'csquare', a square macro..
46
47 FIXME: this duplicates functionality from rsb_eps.c.
48 */
49 #if RSB_ALLOW_STDOUT
50 RSB_FPRINTF(fd,
51 "%%!PS-Adobe-3.0 EPSF-3.0\n"
52 "%%%%Creator: "RSB_PACKAGE_STRING"\n"
53 "%%%%Title: matrix plot\n"
54 "%%%%CreationDate: \n"
55 "%%%%DocumentData: Clean7Bit\n"
56 "%%%%Origin: 0 0\n"
57 "%%%%BoundingBox: 0 0 %d %d\n"
58 "%%%%LanguageLevel: 2 \n"
59 "%%%%Pages: 1\n"
60 "%%%%Page: 1 1\n"
61 "\n"
62 "/csquare {\n"
63 " newpath\n"
64 " 0 0 moveto\n"
65 " 0 -%g rlineto\n"
66 " %g 0 rlineto\n"
67 " 0 %g rlineto\n"
68 " closepath\n"
69 " setrgbcolor\n"
70 " fill\n"
71 "} def\n"
72 "\n"
73 "0 0 moveto\n"
74 "\n",
75 (int)width, (int)height,
76 csw,csh,csw
77 );
78 RSB_FPRINTF(fd,"save /$LIBRSB_DICT 3 dict def $LIBRSB_DICT begin /M {moveto} bind def /Z {gsave currentpoint lineto %g setlinewidth 1 setlinecap stroke grestore} bind def /D {M Z} bind def /K {0.5 0.5 setrgbcolor} bind def\n",1.0);
79 RSB_FPRINTF(fd,"/R {rlineto} bind def\n");
80 RSB_FPRINTF(fd,"/N {newpath} bind def\n");
81 RSB_FPRINTF(fd,"/L {lineto} bind def\n");
82 RSB_FPRINTF(fd,"/C {closepath} bind def\n");
83 RSB_FPRINTF(fd,"/SLW {setlinewidth} bind def\n");
84 RSB_FPRINTF(fd,"/SRGB {setrgbcolor} bind def\n");
85 RSB_FPRINTF(fd,"/SCF {scalefont} bind def\n");
86 RSB_FPRINTF(fd,"/SF {setfont} bind def\n");
87 return RSB_ERR_NO_ERROR;
88 #else /* RSB_ALLOW_STDOUT */
89 return RSB_ERR_UNSUPPORTED_FEATURE;
90 #endif /* RSB_ALLOW_STDOUT */
91 }
92
rsb_get_pixmap_RGB_from_coo(const rsb_coo_idx_t * IA,const rsb_coo_idx_t * JA,rsb_nnz_idx_t nnz,rsb_coo_idx_t rows,rsb_coo_idx_t cols,void * pixmap,rsb_coo_idx_t p_rows,rsb_coo_idx_t p_cols,int br,int bc,rsb_flags_t render_flags)93 static rsb_err_t rsb_get_pixmap_RGB_from_coo(const rsb_coo_idx_t * IA, const rsb_coo_idx_t * JA, rsb_nnz_idx_t nnz, rsb_coo_idx_t rows, rsb_coo_idx_t cols, void * pixmap, rsb_coo_idx_t p_rows, rsb_coo_idx_t p_cols, int br, int bc, rsb_flags_t render_flags)
94 {
95 /**
96 * \ingroup gr_internals
97 *
98 * Will fill the specified pixmap (assumed RGB, sized sizeof(char)*p_cols*rows ) with
99 * non pixels for nonzeros and black pixels for zeros.
100 */
101 rsb_err_t errval = RSB_ERR_NO_ERROR;
102 char * dst;
103 // rsb_coo_idx_t i,j;
104 rsb_nnz_idx_t k;
105 size_t sz;
106 size_t bpp=3;
107 char fgc=0x00,bgc=0x0;
108
109 if(!pixmap || !IA || !JA)
110 return RSB_ERR_BADARGS;
111 /* should check I and JA and rows and cols and nnz */
112 // if(cols>p_cols)
113 // return RSB_ERR_BADARGS;
114
115 /* DANGER : overflow is possible : FIXME */
116 if( RSB_COO_ADD_OVERFLOW(p_rows, p_cols) )
117 {
118 errval = RSB_ERR_LIMITS;
119 RSB_PERR_GOTO(err,RSB_ERRM_ES);
120 }
121
122 dst=pixmap;
123 sz =p_cols;
124 sz*=p_rows;
125 sz*=bpp;
126
127 /*
128 * NOTE : inserting unsorted coefficients is SLOW!
129 * wouldn't be faster to copy and sort ?
130 * FIXME
131 */
132 //RSB_STDOUT("br %d bc %d\n",br,bc);
133
134 if(render_flags & 0x01)
135 {
136 bgc=~bgc;
137 }
138 fgc=~bgc;
139
140 if(br==bc && br==1)
141 {
142 memset(dst,bgc,sz);
143 for(k=0;k<nnz;++k)
144 {
145 dst[bpp*(IA[k]*p_cols+JA[k])+0]=fgc;
146 dst[bpp*(IA[k]*p_cols+JA[k])+1]=fgc;
147 dst[bpp*(IA[k]*p_cols+JA[k])+2]=fgc;
148 }
149 }
150 else
151 {
152 memset(dst,bgc,sz);
153 for(k=0;k<nnz;++k)
154 {
155 if(IA[k]/br < 0 || IA[k]/br>p_rows-1 || JA[k]/bc < 0 || JA[k]/bc>p_cols-1)
156 RSB_ERROR("I %ld JA %ld %ld %ld\n",(long)IA[k]/br,(long)JA[k]/bc,(long)p_rows,(long)p_cols);
157 dst[bpp*((IA[k]/br)*p_cols+JA[k]/bc)+0]=fgc;
158 dst[bpp*((IA[k]/br)*p_cols+JA[k]/bc)+1]=fgc;
159 dst[bpp*((IA[k]/br)*p_cols+JA[k]/bc)+2]=fgc;
160 }
161 }
162 err:
163 RSB_DO_ERR_RETURN(errval)
164 }
165
rsb__do_get_pixmap_RGB_from_matrix(const char * filename,void * pixmap,int width,int height)166 rsb_err_t rsb__do_get_pixmap_RGB_from_matrix(const char * filename, void * pixmap, int width, int height)
167 {
168 /**
169 * \ingroup gr_internals
170
171 * FIXME : needs error handling
172
173 * This function is experimentally used to render the sparse matrix;
174 */
175 rsb_err_t errval = RSB_ERR_NO_ERROR;
176 rsb_coo_idx_t *IA=NULL, *JA=NULL;
177 void *VA=NULL;
178 rsb_coo_idx_t m=0,k=0;
179 rsb_nnz_idx_t nnz=0;
180 #ifdef RSB_NUMERICAL_TYPE_DOUBLE
181 rsb_type_t typecode = RSB_NUMERICAL_TYPE_DOUBLE ;
182 #else /* RSB_NUMERICAL_TYPE_DOUBLE */
183 rsb_type_t typecode = RSB_NUMERICAL_TYPE_DEFAULT;
184 #endif /* RSB_NUMERICAL_TYPE_DOUBLE */
185 rsb_flags_t flags = RSB_FLAG_NOFLAGS;
186 rsb_flags_t render_flags=0x01; /* */
187 int br=1,bc=1;
188 rsb_time_t t=0;
189
190 RSB_DO_FLAG_ADD(flags,RSB_FLAG_WANT_BCSS_STORAGE);
191 RSB_DO_FLAG_ADD(flags,RSB_FLAG_SORTED_INPUT);
192
193 if(!filename || !pixmap)
194 {
195 errval = RSB_ERR_BADARGS;
196 RSB_PERR_GOTO(err,RSB_ERRM_ES);
197 }
198
199 t = - rsb_time();
200 if((errval = rsb__util_mm_load_matrix_f(filename,&IA,&JA,&VA,&m,&k,&nnz,typecode,flags,NULL,NULL)))
201 {
202 RSB_PERR_GOTO(err,RSB_ERRM_ES)
203 }
204 t += rsb_time();
205 // RSB_STDOUT("load : %lg\n",t);
206
207 /* sorting doesn't seem to speed up sparse matrices rendering */
208 t = - rsb_time();
209 // if((errval = rsb__util_sort_row_major_inner(VA,IA,JA,nnz,m,k,typecode,flags)))
210 // {
211 // RSB_PERR_GOTO(err,RSB_ERRM_ES)
212 // }
213 t += rsb_time();
214 // RSB_STDOUT("sort : %lg\n",t);
215
216 if(width <k)
217 bc=(k+width-1)/width ;
218
219 if(height<m)
220 br=(m+height-1)/height;
221
222 if(br<1 || bc<1)
223 {
224 // errval = RSB_ERR_BADARGS;
225 RSB_PERR_GOTO(err,RSB_ERRM_ES);
226 }
227
228 /* rsb__mtx_as_pixmap_resize is optional */
229 if( (errval = rsb__mtx_as_pixmap_resize(VA, IA, JA, nnz, &nnz, m, k, height, width, typecode, flags)))
230 {
231 RSB_PERR_GOTO(err,RSB_ERRM_ES)
232 }
233 else
234 {
235 m=height;
236 k=width;
237 br=bc=1;
238 }
239
240 t = - rsb_time();
241 if( (errval = rsb_get_pixmap_RGB_from_coo(IA, JA, nnz, m, k, pixmap, height, width, br, bc, render_flags)) )
242 {
243 RSB_PERR_GOTO(err,RSB_ERRM_ES)
244 }
245 t += rsb_time();
246 // RSB_STDOUT("render : %lg\n",t);
247
248 err:
249 RSB_CONDITIONAL_FREE(IA);
250 RSB_CONDITIONAL_FREE(JA);
251 RSB_CONDITIONAL_FREE(VA);
252
253 RSB_DO_ERR_RETURN(errval)
254 }
255
rsb__mtx_as_pixmap_resize(void * VA,rsb_coo_idx_t * IA,rsb_coo_idx_t * JA,rsb_nnz_idx_t nnz,rsb_nnz_idx_t * rnnz,rsb_coo_idx_t m,rsb_coo_idx_t k,rsb_coo_idx_t p_rows,rsb_coo_idx_t p_cols,rsb_type_t typecode,rsb_flags_t render_flags)256 rsb_err_t rsb__mtx_as_pixmap_resize(void *VA, rsb_coo_idx_t * IA, rsb_coo_idx_t * JA, rsb_nnz_idx_t nnz, rsb_nnz_idx_t *rnnz, rsb_coo_idx_t m, rsb_coo_idx_t k, rsb_coo_idx_t p_rows, rsb_coo_idx_t p_cols, rsb_type_t typecode, rsb_flags_t render_flags)
257 {
258 /*
259 * \ingroup gr_internals
260 * User shall be allowed to provide RSB_FLAG_SORTED_INPUT even on unsorted input.
261 * However, in that case only contiguous duplicates will be catched.
262 * FIXME : untested
263 * FIXME : missing comments and error handling.
264 * FIXME : missing input sanitizing
265 */
266
267 double rf,cf;/* row and column factors */
268 rsb_nnz_idx_t n;
269 rsb_err_t errval = RSB_ERR_NO_ERROR;
270
271 rf=((double)p_rows)/(double)m;
272 cf=((double)p_cols)/(double)k;
273
274 for(n=0;n<nnz;++n)
275 {
276 IA[n]= (rsb_coo_idx_t)(((double)IA[n]) * rf);
277 JA[n]= (rsb_coo_idx_t)(((double)JA[n]) * cf);
278 }
279 m=p_rows;
280 k=p_cols;
281
282 render_flags &= RSB_FLAG_SORTED_INPUT;
283 if(!RSB_DO_FLAG_HAS(render_flags,RSB_FLAG_SORTED_INPUT))
284 if((errval = rsb__util_sort_row_major_inner(VA,IA,JA,nnz,m,k,typecode,render_flags/*RSB_FLAG_NOFLAGS*/))!=RSB_ERR_NO_ERROR)
285 {
286 errval = RSB_ERR_GENERIC_ERROR;
287 RSB_PERR_GOTO(err,RSB_ERRM_ES)
288 }
289
290 *rnnz = rsb_weed_out_duplicates(IA,JA,VA,nnz,typecode,RSB_FLAG_DUPLICATES_SUM/*RSB_FLAG_DUPLICATES_DEFAULT_HANDLE*/|RSB_FLAG_SORTED_INPUT);
291
292 /* missing error handling here */
293 err:
294 return errval;
295 }
296
297 /* @endcond */
298