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