1 /***************************************************************************
2  * pixel_bit.cpp is part of Math Graphic Library
3  * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru>       *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License  as       *
7  *   published by the Free Software Foundation; either version 3 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Lesser General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include <algorithm>
21 #include "mgl2/canvas.h"
22 #include "mgl2/thread.h"
23 #if MGL_HAVE_OMP
24 #include <omp.h>
25 #endif
26 
27 //-----------------------------------------------------------------------------
pxl_primpx(long id,long n,const void *)28 void mglCanvas::pxl_primpx(long id, long n, const void *)	// NOTE this variant is too slow ... may be later in CUDA???
29 {
30 	mglDrawReg d;	d.set(this,1,1,id);
31 #if !MGL_HAVE_PTHREAD
32 #pragma omp parallel for firstprivate(d)
33 #endif
34 	for(long ii=0;ii<n;ii+=mglNumThr)
35 	{
36 		long i=ii%Width, j=ii/Width;
37 		for(size_t k=0;k<Prm.size();k++)
38 		{
39 			if(Stop)	break;
40 			const mglPrim &p=GetPrm(k);
41 			d.PDef = p.n3;	d.pPos = p.s;
42 			d.ObjId = p.id;	d.PenWidth=p.w;
43 			d.angle = p.angl;
44 			if(p.type==2 || p.type==3) d.PDef = p.m;
45 			switch(p.type)
46 			{
47 			case 0:	mark_pix(i,j,Pnt[p.n1],p.n4,p.s,&d);	break;
48 			case 1:	line_pix(i,j,Pnt[p.n1],Pnt[p.n2],&d);	break;
49 			case 2:	trig_pix(i,j,Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],true,&d);	break;
50 			case 3:	quad_pix(i,j,Pnt[p.n1],Pnt[p.n2],Pnt[p.n3],Pnt[p.n4],&d);	break;
51 			case 4:	glyph_pix(i,j,p,&d);	break;
52 			}
53 		}
54 	}
55 }
56 //-----------------------------------------------------------------------------
quad_pix(long i,long j,const mglPnt & p1,const mglPnt & p2,const mglPnt & p3,const mglPnt & p4,const mglDrawReg * d)57 void mglCanvas::quad_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d)
58 {
59 	if(!visible(i,j,d->m, d->PenWidth,d->angle))	return;
60 	mglPnt d1(p2-p1), d2(p3-p1), d3(p4+p1-p2-p3);
61 	float dd = d1.x*d2.y-d1.y*d2.x;
62 	float dsx =-4*(d2.y*d3.x - d2.x*d3.y)*d1.y;
63 	float dsy = 4*(d2.y*d3.x - d2.x*d3.y)*d1.x;
64 	float xx = (i-p1.x), yy = (j-p1.y), s;
65 	s = dsx*xx + dsy*yy + (dd+d3.y*xx-d3.x*yy)*(dd+d3.y*xx-d3.x*yy);
66 	if(s<0)	return;	// no solution
67 	s = sqrt(s);
68 	float qu = d3.x*yy - d3.y*xx + dd + s, u=-1;
69 	float qv = d3.y*xx - d3.x*yy + dd + s, v=-1;
70 	if(qu && qv)
71 	{
72 		u = 2.f*(d2.y*xx - d2.x*yy)/qu;
73 		v = 2.f*(d1.x*yy - d1.y*xx)/qv;
74 	}
75 	if(u*(1.f-u)<0.f || v*(1.f-v)<0.f)	// first root bad
76 	{
77 		qu = d3.x*yy - d3.y*xx + dd - s;
78 		qv = d3.y*xx - d3.x*yy + dd - s;
79 		u = v = -1.f;
80 		if(qu && qv)
81 		{
82 			u = 2.f*(d2.y*xx - d2.x*yy)/qu;
83 			v = 2.f*(d1.x*yy - d1.y*xx)/qv;
84 		}
85 		if(u*(1.f-u)<0.f || v*(1.f-v)<0.f)	return;	// second root bad
86 	}
87 	mglPnt p(p1+d1*u+d2*v+d3*(u*v));
88 	if(mgl_isnan(p.u) && mgl_isnum(p.v))
89 	{
90 		mglPoint n1(mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z));
91 		mglPoint n2(mglPoint(p2.x-p4.x,p2.y-p4.y,p2.z-p4.z)^mglPoint(p3.x-p4.x,p3.y-p4.y,p3.z-p4.z));
92 		p.u = (n1.x+n2.x)*0.5;
93 		p.v = (n1.y+n2.y)*0.5;
94 		p.w = (n1.z+n2.z)*0.5;
95 	}
96 	unsigned char r[4];	col2int(p,r,d->ObjId);
97 	if(r[3])	pnt_plot(i,j,p.z,r,d->ObjId);
98 }
99 //-----------------------------------------------------------------------------
trig_pix(long i,long j,const mglPnt & p1,const mglPnt & p2,const mglPnt & p3,bool anorm,const mglDrawReg * d)100 void mglCanvas::trig_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d)
101 {
102 	if(!visible(i,j,d->m, d->PenWidth,d->angle))	return;
103 	mglPnt d1(p2-p1), d2(p3-p1);
104 	float dd = d2.x*d1.y - d1.x*d2.y;
105 	if(fabs(dd)<1e-5)	return;		// points lies on the same line
106 	float dyv =-d1.x/dd, dxv = d1.y/dd, dyu = d2.x/dd, dxu =-d2.y/dd;
107 	float xx = (i-p1.x), yy = (j-p1.y);
108 	float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;
109 	if(u<0 || v<0 || u+v>1)	return;
110 	mglPnt p(p1+d1*u+d2*v);
111 	if(mgl_isnan(p.u) && mgl_isnum(p.v) && anorm)
112 	{	mglPoint nr(mglPoint(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z)^mglPoint(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z));
113 		p.u = nr.x;	p.v = nr.y;	p.w = nr.z;	}
114 	unsigned char r[4];
115 	col2int(p,r,d->ObjId);
116 	if(r[3])	pnt_plot(i,j,p.z,r,d->ObjId);
117 }
118 //-----------------------------------------------------------------------------
line_pix(long i,long j,const mglPnt & p1,const mglPnt & p2,const mglDrawReg * dr)119 void mglCanvas::line_pix(long i, long j, const mglPnt &p1, const mglPnt &p2, const mglDrawReg *dr)
120 {
121 	float xx = (i-p1.x), yy = (j-p1.y);
122 	mglPnt d(p2-p1);
123 	float dd = hypot(d.x, d.y);
124 	float dxv = d.y/dd, dyv =-d.x/dd, dxu = d.x/dd, dyu = d.y/dd;
125 	float u = dxu*xx+dyu*yy, v = dxv*xx+dyv*yy;	v = v*v;
126 	if(u<0)			v += u*u;
127 	else if(u>dd)	v += (u-dd)*(u-dd);
128 	float pw=dr->PenWidth, dpw=3*pen_delta;
129 	if(dr->ObjId==HighId)	{	pw *= 2;	dpw=2*pen_delta;	}
130 	if(v>pw*pw || !(dr->PDef & ( (uint64_t)1<<long(fmod(dr->pPos+u/pw, 16)) ) ))	return;
131 	mglPnt p(p1+d*(u/dd));
132 	unsigned char r[4];
133 	col2int(p,r,dr->ObjId);
134 	r[3] = v<(pw-1)*(pw-1)/4 ? 255 : mgl_sline(255,dpw*(sqrt(v)+(1-pw)/2));
135 	float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
136 	if(r[3])	pnt_plot(i,j,p.z+dz,r,dr->ObjId);
137 }
138 //-----------------------------------------------------------------------------
pnt_pix(long i,long j,const mglPnt & p,const mglDrawReg * dr)139 void mglCanvas::pnt_pix(long i, long j, const mglPnt &p, const mglDrawReg *dr)
140 {
141 	float pw=3*dr->PenWidth,dpw=3*pen_delta;
142 	if(dr->ObjId==HighId)	{	pw *= 2;	dpw=2*pen_delta;	}
143 	unsigned char cs[4];
144 	col2int(p,cs,dr->ObjId);
145 	float xx = (i-p.x), yy = (j-p.y), v = xx*xx+yy*yy;
146 	if(cs[3]==0 || v>(10/dpw+pw)*(10/dpw+pw))	return;
147 	if(v<(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],dpw*(sqrt(v)+(1-pw)/2));
148 	if(cs[3])	pnt_plot(i,j,p.z,cs,dr->ObjId);
149 }
150 //-----------------------------------------------------------------------------
mark_pix(long i,long j,const mglPnt & q,char type,mreal size,mglDrawReg * d)151 void mglCanvas::mark_pix(long i, long j, const mglPnt &q, char type, mreal size, mglDrawReg *d)
152 {
153 	unsigned char cs[4];	col2int(q,cs,d->ObjId);	cs[3] = size>0 ? 255 : 255*q.t;
154 	mglPnt p0=q,p1=q,p2=q,p3=q;
155 	mreal ss=fabs(size);
156 
157 	if(type=='.' || ss==0)
158 	{
159 		if(d)	d->PenWidth = ss?ss:sqrt(font_factor/400);
160 		pnt_pix(i,j,q,d);
161 	}
162 	else
163 	{
164 		if(d)
165 		{
166 			d->PDef = MGL_SOLID_MASK;	d->angle = 0;
167 			d->PenWidth*=fabs(50*size);
168 			if(d->PenWidth<1)	d->PenWidth=1;
169 		}
170 		if(!strchr("xsSoO",type))	ss *= 1.1;
171 		switch(type)
172 		{
173 		case 'P':
174 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
175 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
176 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
177 			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
178 		case '+':
179 			p0.x = q.x-ss;	p0.y = q.y;	p1.x = q.x+ss;	p1.y = q.y;	line_pix(i,j,p0,p1,d);
180 			p2.x = q.x;	p2.y = q.y-ss;	p3.x = q.x;	p3.y = q.y+ss;	line_pix(i,j,p2,p3,d);
181 			break;
182 		case 'X':
183 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
184 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
185 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
186 			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
187 		case 'x':
188 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y+ss;	line_pix(i,j,p0,p1,d);
189 			p2.x = q.x+ss;	p2.y = q.y-ss;	p3.x = q.x-ss;	p3.y = q.y+ss;	line_pix(i,j,p2,p3,d);
190 			break;
191 		case 'S':
192 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x-ss;	p1.y = q.y+ss;
193 			p2.x= q.x+ss;	p2.y= q.y+ss;	p3.x = q.x+ss;	p3.y = q.y-ss;
194 			quad_pix(i,j,p0,p1,p3,p2,d);
195 		case 's':
196 			p0.x = q.x-ss;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y-ss;
197 			p2.x = q.x+ss;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y+ss;
198 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
199 			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
200 			break;
201 		case 'D':
202 			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
203 			p2.x= q.x;	p2.y= q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
204 			quad_pix(i,j,p0,p1,p3,p2,d);
205 		case 'd':
206 			p0.x = q.x;	p0.y = q.y-ss;	p1.x = q.x+ss;	p1.y = q.y;
207 			p2.x = q.x;	p2.y = q.y+ss;	p3.x = q.x-ss;	p3.y = q.y;
208 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
209 			line_pix(i,j,p2,p3,d);	line_pix(i,j,p3,p0,d);
210 			break;
211 		case 'Y':
212 			p1.x = q.x;	p1.y = q.y-ss;	line_pix(i,j,q,p1,d);
213 			p2.x = q.x-0.8*ss;	p2.y = q.y+0.6*ss;	line_pix(i,j,q,p2,d);
214 			p3.x = q.x+0.8*ss;	p3.y = q.y+0.6*ss;	line_pix(i,j,q,p3,d);
215 			break;
216 		case '*':
217 			p0.x = q.x-ss;		p0.y = q.y;
218 			p1.x = q.x+ss;		p1.y = q.y;	line_pix(i,j,p0,p1,d);
219 			p0.x = q.x-0.6*ss;	p0.y = q.y-0.8*ss;
220 			p1.x = q.x+0.6*ss;	p1.y = q.y+0.8*ss;	line_pix(i,j,p0,p1,d);
221 			p0.x = q.x-0.6*ss;	p0.y = q.y+0.8*ss;
222 			p1.x = q.x+0.6*ss;	p1.y = q.y-0.8*ss;	line_pix(i,j,p0,p1,d);
223 			break;
224 		case 'T':
225 			p0.x = q.x-ss;	p0.y = q.y-ss/2;
226 			p1.x = q.x+ss;	p1.y = q.y-ss/2;
227 			p2.x= q.x;		p2.y= q.y+ss;
228 			trig_pix(i,j,p0,p1,p2,false,d);
229 		case '^':
230 			p0.x = q.x-ss;	p0.y = q.y-ss/2;
231 			p1.x = q.x+ss;	p1.y = q.y-ss/2;
232 			p2.x= q.x;		p2.y= q.y+ss;
233 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
234 			line_pix(i,j,p2,p0,d);	break;
235 		case 'V':
236 			p0.x = q.x-ss;	p0.y = q.y+ss/2;
237 			p1.x = q.x+ss;	p1.y = q.y+ss/2;
238 			p2.x= q.x;		p2.y= q.y-ss;
239 			trig_pix(i,j,p0,p1,p2,false,d);
240 		case 'v':
241 			p0.x = q.x-ss;	p0.y = q.y+ss/2;
242 			p1.x = q.x+ss;	p1.y = q.y+ss/2;
243 			p2.x= q.x;		p2.y= q.y-ss;
244 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
245 			line_pix(i,j,p2,p0,d);	break;
246 		case 'L':
247 			p0.x = q.x+ss/2;	p0.y = q.y+ss;
248 			p1.x = q.x+ss/2;	p1.y = q.y-ss;
249 			p2.x= q.x-ss;		p2.y= q.y;
250 			trig_pix(i,j,p0,p1,p2,false,d);
251 		case '<':
252 			p0.x = q.x+ss/2;	p0.y = q.y+ss;
253 			p1.x = q.x+ss/2;	p1.y = q.y-ss;
254 			p2.x= q.x-ss;		p2.y= q.y;
255 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
256 			line_pix(i,j,p2,p0,d);	break;
257 		case 'R':
258 			p0.x = q.x-ss/2;	p0.y = q.y+ss;
259 			p1.x = q.x-ss/2;	p1.y = q.y-ss;
260 			p2.x= q.x+ss;		p2.y= q.y;
261 			trig_pix(i,j,p0,p1,p2,false,d);
262 		case '>':
263 			p0.x = q.x-ss/2;	p0.y = q.y+ss;
264 			p1.x = q.x-ss/2;	p1.y = q.y-ss;
265 			p2.x= q.x+ss;		p2.y= q.y;
266 			line_pix(i,j,p0,p1,d);	line_pix(i,j,p1,p2,d);
267 			line_pix(i,j,p2,p0,d);	break;
268 		case 'O':
269 			{
270 				float xx = (i-q.x), yy = (j-q.y);
271 				float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
272 				if(xx*xx+yy*yy<ss*ss && cs[3])	pnt_plot(i,j,q.z+dz,cs,d->ObjId);
273 			}
274 		case 'o':
275 			{
276 				float pw=d->PenWidth;
277 				float xx = (i-q.x), yy = (j-q.y), v = hypot(xx,yy);
278 				v = (v-ss)*(v-ss);
279 //				if(v>pw*pw)	return;
280 				if(v>(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],2*(sqrt(v)+(1-pw)/2));
281 				float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
282 				if(cs[3])	pnt_plot(i,j,q.z+dz,cs,d->ObjId);
283 			}
284 			break;
285 		case 'C':
286 			pnt_pix(i,j,q,d);
287 			{
288 				float pw=d->PenWidth;
289 				float xx = (i-q.x), yy = (j-q.y), v = hypot(xx,yy);
290 				v = (v-ss)*(v-ss);
291 //				if(v>pw*pw)	return;
292 				if(v>(pw-1)*(pw-1)/4)	cs[3] = mgl_sline(cs[3],2*(sqrt(v)+(1-pw)/2));
293 				float dz = Width>2 ? 1 : 1e-5*Width;		// provide additional height to be well visible on the surfaces
294 				if(cs[3])	pnt_plot(i,j,q.z+dz,cs,d->ObjId);
295 			}
296 			break;
297 		}
298 	}
299 }
300 //-----------------------------------------------------------------------------
glyph_pix(long i,long j,const mglPrim & P,mglDrawReg * d)301 void mglCanvas::glyph_pix(long i, long j, const mglPrim &P, mglDrawReg *d)
302 {
303 	float phi = GetGlyphPhi(Pnt[P.n2],P.w);
304 	if(mgl_isnan(phi))	return;
305 
306 	if(d)	{	d->PDef = MGL_SOLID_MASK;	d->angle = 0;	d->PenWidth=1;	}
307 	mglPnt p=Pnt[P.n1];
308 	mreal pf=sqrt((Bp.b[0]*Bp.b[0]+Bp.b[1]*Bp.b[1]+Bp.b[3]*Bp.b[3]+Bp.b[4]*Bp.b[4])/2), f = P.p*pf;
309 
310 	mglMatrix M;
311 	M.b[0] = M.b[4] = M.b[8] = P.s;
312 	M.RotateN(phi,0,0,1);
313 	M.x=p.x;	M.y=p.y;	M.z=p.z;	M.pf = 1;
314 	p.u *= pf;	p.v *= pf;
315 
316 	const mglGlyph &g = Glf[P.n4];
317 	if(P.n3&8)
318 	{
319 		if(!(P.n3&4))	glyph_lpix(i,j,&M,p,f,true, d);
320 		glyph_lpix(i,j,&M,p,f,false, d);
321 	}
322 	else
323 	{
324 		if(!(P.n3&4))	glyph_fpix(i,j,&M,p,f,g, d);
325 		glyph_wpix(i,j,&M,p,f,g, d);
326 	}
327 }
328 //-----------------------------------------------------------------------------
glyph_fpix(long i,long j,const mglMatrix * M,const mglPnt & pp,mreal f,const mglGlyph & g,const mglDrawReg * d)329 void mglCanvas::glyph_fpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
330 {
331 	if(!g.trig || g.nt<=0)	return;
332 	mglPnt q0=pp, q1=pp, q2=pp;
333 	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=NAN;
334 	for(long ik=0;ik<g.nt;ik++)
335 	{
336 		long ii = 6*ik;	mglPoint p;
337 		p.Set(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
338 		PostScale(M,p);	q0.x = p.x;	q0.y = p.y;	q0.z = p.z;
339 		ii+=2;	p.Set(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
340 		PostScale(M,p);	q1.x = p.x;	q1.y = p.y;	q1.z = p.z;
341 		ii+=2;	p.Set(f*g.trig[ii]+pp.u,f*g.trig[ii+1]+pp.v,0);
342 		PostScale(M,p);	q2.x = p.x;	q2.y = p.y;	q2.z = p.z;
343 		trig_pix(i,j,q0,q1,q2,false,d);
344 	}
345 }
346 //-----------------------------------------------------------------------------
glyph_wpix(long i,long j,const mglMatrix * M,const mglPnt & pp,mreal f,const mglGlyph & g,const mglDrawReg * d)347 void mglCanvas::glyph_wpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, const mglGlyph &g, const mglDrawReg *d)
348 {
349 	if(!g.line || g.nl<=0)	return;
350 	long il=0;
351 	mglPnt q0=pp, q1=pp;	q0.u=q0.v=q1.u=q1.v=NAN;
352 	mglPoint p1,p2;
353 	for(long ik=0;ik<g.nl;ik++)
354 	{
355 		long ii = 2*ik;
356 		if(g.line[ii]==0x3fff && g.line[ii+1]==0x3fff)	// line breakthrough
357 		{	il = ik+1;	continue;	}
358 		else if(ik==g.nl-1 || (g.line[ii+2]==0x3fff && g.line[ii+3]==0x3fff))
359 		{	// enclose the circle. May be in future this block should be commented
360 			p1.Set(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);	ii=2*il;
361 			p2.Set(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);
362 		}
363 		else
364 		{	// normal line
365 			p1.Set(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);	ii+=2;
366 			p2.Set(f*g.line[ii]+pp.u,f*g.line[ii+1]+pp.v,0);
367 		}
368 		PostScale(M,p1);	PostScale(M,p2);
369 		q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
370 		q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
371 		line_pix(i,j,q0,q1,d);
372 	}
373 }
374 //-----------------------------------------------------------------------------
glyph_lpix(long i,long j,const mglMatrix * M,const mglPnt & pp,mreal f,bool solid,const mglDrawReg * d)375 void mglCanvas::glyph_lpix(long i, long j, const mglMatrix *M, const mglPnt &pp, mreal f, bool solid, const mglDrawReg *d)
376 {
377 	mglPnt q0=pp,q1=pp,q2=pp,q3=pp;
378 	q0.u=q0.v=q1.u=q1.v=q2.u=q2.v=q3.u=q3.v=NAN;
379 	mglPoint p1,p2,p3,p4;
380 
381 	mreal dy = 0.004;
382 	p1.Set(pp.u,pp.v-dy,0);	PostScale(M,p1);
383 	p2.Set(pp.u,pp.v+dy,0);	PostScale(M,p2);
384 	p3.Set(fabs(f)+pp.u,pp.v+dy,0);	PostScale(M,p3);
385 	p4.Set(fabs(f)+pp.u,pp.v-dy,0);	PostScale(M,p4);
386 
387 	q0.x = p1.x;	q0.y = p1.y;	q0.z = p1.z;
388 	q1.x = p2.x;	q1.y = p2.y;	q1.z = p2.z;
389 	q2.x = p3.x;	q2.y = p3.y;	q2.z = p3.z;
390 	q3.x = p4.x;	q3.y = p4.y;	q3.z = p4.z;
391 
392 	if(solid)	quad_pix(i,j,q0,q1,q3,q2,d);
393 	else
394 	{
395 		line_pix(i,j,q0,q1,d);	line_pix(i,j,q2,q1,d);
396 		line_pix(i,j,q0,q3,d);	line_pix(i,j,q2,q3,d);
397 	}
398 }
399 //-----------------------------------------------------------------------------
400