/*************************************************************************** * canvas.h is part of Math Graphic Library * Copyright (C) 2007-2016 Alexey Balakin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef MGL_CANVAS_H #define MGL_CANVAS_H #include "mgl2/base.h" //----------------------------------------------------------------------------- struct GifFileType; //----------------------------------------------------------------------------- /// Structure for drawing axis and ticks struct MGL_EXPORT mglAxis { mglAxis() : dv(0),ds(0),d(0),ns(0), v0(0),v1(0),v2(0),o(NAN), f(0), ch(0), pos('t'),sh(0),inv(false) {} mglAxis(const mglAxis &aa) : dv(aa.dv),ds(aa.ds),d(aa.d),ns(aa.ns), t(aa.t),fact(aa.fact),stl(aa.stl), dir(aa.dir),a(aa.a),b(aa.b),org(aa.org), v0(aa.v0),v1(aa.v1),v2(aa.v2),o(aa.o), f(aa.f),txt(aa.txt), ch(aa.ch), pos(aa.pos),sh(aa.sh),inv(aa.inv) {} #if MGL_HAVE_RVAL mglAxis(mglAxis &&aa) : dv(aa.dv),ds(aa.ds),d(aa.d),ns(aa.ns), t(aa.t),fact(aa.fact),stl(aa.stl), dir(aa.dir),a(aa.a),b(aa.b),org(aa.org), v0(aa.v0),v1(aa.v1),v2(aa.v2),o(aa.o), f(aa.f),txt(aa.txt), ch(aa.ch), pos(aa.pos),sh(aa.sh),inv(aa.inv) {} #endif inline void AddLabel(const wchar_t *lbl, mreal v) { if(mgl_isfin(v)) txt.push_back(mglText(lbl,"",v)); } inline void AddLabel(const std::wstring &lbl, mreal v) { if(mgl_isfin(v)) txt.push_back(mglText(lbl,v)); } inline void Clear() { dv=ds=d=v0=v1=v2=sh=0; o=NAN; ns=f=0; pos = 't'; inv=false; fact.clear(); stl.clear(); t.clear(); txt.clear(); } mreal dv,ds; ///< Actual step for ticks and subticks. mreal d; ///< Step for axis ticks (if positive) or its number (if negative). int ns; ///< Number of axis subticks. std::wstring t; ///< Tick template (set "" to use default one ("%.2g" in simplest case)) std::wstring fact; ///< Factor which should be placed after number (like L"\pi") std::string stl; ///< Tick styles (default is ""=>"3m") mglPoint dir; ///< Axis direction mglPoint a,b; ///< Directions of over axis mglPoint org; mreal v0; ///< Center of axis cross section mreal v1; ///< Minimal axis range. mreal v2; ///< Maximal axis range. mreal o; ///< Point of starting ticks numbering (if NAN then Org is used). int f; ///< Flag 0x1 - time, 0x2 - manual, 0x4 - fixed dv std::vector txt; ///< Axis labels char ch; ///< Character of axis (like 'x','y','z','c') char pos; ///< Text position ('t' by default, or 'T' for opposite) mreal sh; ///< Extra shift of ticks and axis labels bool inv; ///< Inverse automatic origin position mreal angl; ///< Manual for ticks rotation (if not NAN) }; //----------------------------------------------------------------------------- class mglCanvas; /// Structure for drawing region struct MGL_EXPORT mglDrawReg { mglDrawReg() {} mglDrawReg(const mglDrawReg &aa) : PDef(aa.PDef),angle(aa.angle),ObjId(aa.ObjId),PenWidth(aa.PenWidth),pPos(aa.pPos) ,x1(aa.x1),x2(aa.x2),y1(aa.y1),y2(aa.y2) {} #if MGL_HAVE_RVAL mglDrawReg(mglDrawReg &&aa) : PDef(aa.PDef),angle(aa.angle),ObjId(aa.ObjId),PenWidth(aa.PenWidth),pPos(aa.pPos) ,x1(aa.x1),x2(aa.x2),y1(aa.y1),y2(aa.y2) {} #endif inline const mglDrawReg &operator=(const mglDrawReg &aa) { memcpy(this,&aa,sizeof(mglDrawReg)); return aa; } union { uint64_t PDef; unsigned char m[8]; }; int angle; ///< mask rotation values in degrees int ObjId; mreal PenWidth, pPos; int x1,x2,y1,y2; void set(mglCanvas *gr, int nx, int ny, int m); }; //----------------------------------------------------------------------------- /// Structure contains everything for drawing struct MGL_EXPORT mglDrawDat { mglDrawDat() {} mglDrawDat(const mglDrawDat &aa) : Pnt(aa.Pnt),Prm(aa.Prm),Sub(aa.Sub),Ptx(aa.Ptx),Glf(aa.Glf),Txt(aa.Txt) {} #if MGL_HAVE_RVAL mglDrawDat(mglDrawDat &&aa) : Pnt(aa.Pnt),Prm(aa.Prm),Sub(aa.Sub),Ptx(aa.Ptx),Glf(aa.Glf),Txt(aa.Txt) {} #endif inline const mglDrawDat&operator=(const mglDrawDat &aa) { Pnt=aa.Pnt; Prm=aa.Prm; Ptx=aa.Ptx; Glf=aa.Glf; Txt=aa.Txt; Sub=aa.Sub; return aa; } mglStack Pnt; ///< Internal points mglStack Prm; ///< Primitives (lines, triangles and so on) -- need for export std::vector Sub; ///< InPlot regions std::vector Ptx; ///< Text labels for mglPrim std::vector Glf; ///< Glyphs data std::vector Txt; ///< Pointer to textures }; #if defined(_MSC_VER) template class MGL_EXPORT std::vector; #endif //----------------------------------------------------------------------------- union mglRGBA { uint32_t c; unsigned char r[4]; }; //----------------------------------------------------------------------------- /// Class contains all functionality for creating different mathematical plots class MGL_EXPORT mglCanvas : public mglBase { friend struct mglPrim; friend struct mglDrawReg; public: using mglBase::Light; mglCanvas(int w=800, int h=600); virtual ~mglCanvas(); /// Set default parameter for plotting void DefaultPlotParam(); /// Set angle of view indepently from mglCanvas::Rotate() virtual void View(mreal tetx,mreal tetz,mreal tety=0); /// Zoom in or zoom out (if Zoom(0, 0, 1, 1)) a part of picture virtual void Zoom(mreal x1, mreal y1, mreal x2, mreal y2); /// Restore image after View() and Zoom() inline void Restore() { Zoom(0,0,1,1); } /// Clear transformation matrix. inline void Identity(bool rel=false) { InPlot(0,1,0,1,rel); } inline void Identity(mglMatrix &M, bool rel=false) { InPlot(M,0,1,0,1,rel); } /// Push transformation matrix into stack void Push(); /// Set PlotFactor inline void SetPlotFactor(mreal val) { if(val<=0) {B.pf=1.55; set(MGL_AUTO_FACTOR);} else {B.pf=val; clr(MGL_AUTO_FACTOR);} } /// Get PlotFactor inline mreal GetPlotFactor() { return B.pf; } /// Pop transformation matrix from stack inline void Pop() { B = stack.back(); stack.pop_back(); } /// Clear up the frame virtual void Clf(mglColor back=NC); virtual void Clf(const char *col); /// Put further plotting in cell of stick rotated on angles tet, phi void StickPlot(int num, int i, mreal tet, mreal phi); /// Put further plotting in cell of stick sheared on sx, sy void ShearPlot(int num, int i, mreal sx, mreal sy, mreal xd, mreal yd); /// Put further plotting in some region of whole frame surface. inline void InPlot(mreal x1,mreal x2,mreal y1,mreal y2,bool rel=true) { InPlot(B,x1,x2,y1,y2,rel); } void InPlot(mreal x1,mreal x2,mreal y1,mreal y2, const char *style); void InPlot(mglMatrix &M,mreal x1,mreal x2,mreal y1,mreal y2,bool rel=true); /// Add title for current subplot/inplot void Title(const char *title,const char *stl="#",mreal size=-2); void Title(const wchar_t *title,const char *stl="#",mreal size=-2); /// Set aspect ratio for further plotting. void Aspect(mreal Ax,mreal Ay,mreal Az); /// Shear a further plotting. void Shear(mreal Sx,mreal Sy); /// Rotate a further plotting. void Rotate(mreal TetX,mreal TetZ,mreal TetY=0); /// Rotate a further plotting around vector {x,y,z}. void RotateN(mreal Tet,mreal x,mreal y,mreal z); /// Set perspective (in range [0,1)) for plot. Set to zero for switching off. Return the current perspective. void Perspective(mreal a, bool req=true) { if(req) persp = Bp.pf = a; else Bp.pf = persp?persp:fabs(a); } /// Set size of frame in pixels. Normally this function is called internaly. virtual void SetSize(int w,int h,bool clf=true); /// Get ratio (mreal width)/(mreal height). mreal GetRatio() const MGL_FUNC_PURE; /// Get bitmap data prepared for saving to file virtual unsigned char **GetRGBLines(long &w, long &h, unsigned char *&f, bool alpha=false); /// Get RGB bitmap of current state image. virtual const unsigned char *GetBits(); /// Get RGBA bitmap of background image. const unsigned char *GetBackground() { return GB; }; /// Get RGBA bitmap of current state image. const unsigned char *GetRGBA() { Finish(); return G4; } /// Get width of the image int GetWidth() const { return Width; } /// Get height of the image int GetHeight() const { return Height; } /// Combine plots from 2 canvases. Result will be saved into this. void Combine(const mglCanvas *gr); /// Rasterize current plot and set it as background image void Rasterize(); /// Load image for background from file void LoadBackground(const char *fname, double alpha=1); /// Fill background image by specified color void FillBackground(const mglColor &cc); inline mreal GetDelay() const { return Delay; } inline void SetDelay(mreal d) { Delay=d; } /// Calculate 3D coordinate {x,y,z} for screen point {xs,ys} mglPoint CalcXYZ(int xs, int ys, bool real=false) const MGL_FUNC_PURE; /// Calculate screen point {xs,ys} for 3D coordinate {x,y,z} void CalcScr(mglPoint p, int *xs, int *ys) const; mglPoint CalcScr(mglPoint p) const; /// Set object/subplot id inline void SetObjId(long id) { ObjId = id; } /// Get object id inline int GetObjId(long xs,long ys) const { register long i=xs+Width*ys; return (i>=0 && i &leg, int where=3, const char *font="#", const char *opt="") { Legend(leg,(where&1)?1:0,(where&2)?1:0,font,opt); } /// Draw legend strings text at position (x, y) by font with size void Legend(const std::vector &leg, mreal x, mreal y, const char *font="#", const char *opt=""); /// Number of marks in legend sample inline void SetLegendMarks(int num=1) { LegendMarks = num>0?num:1; } /// Draw table for values val along given direction with row labels text at given position void Table(mreal x, mreal y, HCDT val, const wchar_t *text, const char *fnt, const char *opt); void StartAutoGroup (const char *); void EndGroup(); /// Set extra shift for tick and axis labels inline void SetTickShift(mglPoint p) { ax.sh = p.x; ay.sh = p.y; az.sh = p.z; ac.sh = p.c; } /// Get rotation angle for glyph float GetGlyphPhi(const mglPnt &q, float phi); // Following arrays are open for advanced users only. It is not recommended to change them directly float *Z; ///< Height for given level in Z-direction (size 3*width*height) unsigned char *C; ///< Picture for given level in Z-direction (size 3*4*width*height) int *OI; ///< ObjId arrays (size width*height) /// Plot point p with color c void pnt_plot(long x,long y,mreal z,const unsigned char c[4], int obj_id); void pnt_fast(long x,long y,mreal z,const unsigned char c[4], int obj_id); /// preparing primitives for 2d export or bitmap drawing (0 default, 1 for 2d vector, 2 for 3d vector) void PreparePrim(int fast); inline uint32_t GetPntCol(long i) const { return pnt_col[i]; } inline uint32_t GetPrmCol(long i, bool sort=true) const { return GetColor(GetPrm(i, sort)); } /// Set the size of semi-transparent area around lines, marks, ... inline void SetPenDelta(float d) { pen_delta = 1.5*fabs(d); } protected: mreal Delay; ///< Delay for animation in seconds // NOTE: Z should be float for reducing space and for compatibility reasons unsigned char *G4; ///< Final picture in RGBA format. Prepared in Finish(). unsigned char *G; ///< Final picture in RGB format. Prepared in Finish(). unsigned char *GB; ///< Background picture in RGBA format. std::vector DrwDat; ///< Set of ALL drawing data for each frames int LegendMarks; ///< Number of marks in the Legend unsigned char BDef[4]; ///< Background color mglAxis ax,ay,az,ac;///< Axis parameters int TuneTicks; ///< Draw tuned ticks with extracted common component mreal FactorPos; ///< Position of axis ticks factor (0 at Min, 1 at Max, 1.1 is default) mreal TickLen; ///< Length of tiks (subticks length is sqrt(1+st_t)=1.41... times smaller) char AxisStl[32]; ///< Axis line style. Default is "k" char TickStl[32]; ///< Tick line style. Default is "k" char SubTStl[32]; ///< Subtick line style. Default is "k" mreal st_t; ///< Subtick-to-tick ratio (ls=lt/sqrt(1+st_t)). Default is 1. int CurFrameId; ///< Number of automaticle created frames int Width; ///< Width of the image int Height; ///< Height of the image int Depth; ///< Depth of the image mreal inW, inH; ///< Width and height of last InPlot mreal inX, inY; ///< Coordinates of last InPlot mglLight light[10]; ///< Light sources // TODO move to mglBlock mreal FogDist; ///< Inverse fog distance (fog ~ exp(-FogDist*Z)) mreal FogDz; ///< Relative shift of fog /// Auto adjust ticks void AdjustTicks(mglAxis &aa, bool ff); /// Prepare labels for ticks void LabelTicks(mglAxis &aa); /// Draw axis void DrawAxis(mglAxis &aa, bool text=true, char arr=0,const char *stl="",mreal angl=NAN); /// Draw axis grid lines void DrawGrid(mglAxis &aa, bool at_tick=false); /// Update axis ranges inline void UpdateAxis() { ax.v0=Org.x; ay.v0=Org.y; az.v0=Org.z; ac.v0=Org.c; ax.v1=Min.x; ay.v1=Min.y; az.v1=Min.z; ac.v1=Min.c; ax.v2=Max.x; ay.v2=Max.y; az.v2=Max.z; ac.v2=Max.c; } /// Clear ZBuffer only void ClfZB(bool force=false); /// Scale coordinates and cut off some points bool ScalePoint(const mglMatrix *M, mglPoint &p, mglPoint &n, bool use_nan=true) const; void LightScale(const mglMatrix *M); ///< Additionally scale positions of light sources void LightScale(const mglMatrix *M, mglLight &l); ///< Additionally scale positions of light /// Push drawing data (for frames only). NOTE: can be VERY large long PushDrwDat(); /// Retur color for primitive depending lighting uint32_t GetColor(const mglPrim &p) const MGL_FUNC_PURE; mreal GetOrgX(char dir, bool inv=false) const MGL_FUNC_PURE; ///< Get Org.x (parse NAN value) mreal GetOrgY(char dir, bool inv=false) const MGL_FUNC_PURE; ///< Get Org.y (parse NAN value) mreal GetOrgZ(char dir, bool inv=false) const MGL_FUNC_PURE; ///< Get Org.z (parse NAN value) void mark_plot(long p, char type, mreal size=1); void arrow_plot(long p1, long p2, char st); void line_plot(long p1, long p2); void trig_plot(long p1, long p2, long p3); void quad_plot(long p1, long p2, long p3, long p4); void Glyph(mreal x, mreal y, mreal f, int style, long icode, mreal col); mreal text_plot(long p,const wchar_t *text,const char *fnt,mreal size=-1,mreal sh=0,mreal col=-('k'), bool rot=true); void add_prim(mglPrim &a); ///< add primitive to list void arrow_draw(const mglPnt &p1, const mglPnt &p2, char st, mreal size, const mglDrawReg *d); virtual void mark_draw(const mglPnt &p, char type, mreal size, mglDrawReg *d); virtual void line_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d); virtual void trig_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d); virtual void quad_draw(const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d); virtual void pnt_draw(const mglPnt &p, const mglDrawReg *d); void arrow_draw(long n1, long n2, char st, float ll); void arrow_plot_3d(long n1, long n2, char st, float ll); void glyph_draw(const mglPrim &P, mglDrawReg *d); bool IsSame(const mglPrim &pr,mreal wp,mglColor cp,int st); // restore normalized coordinates from screen ones mglPoint RestorePnt(mglPoint ps, bool norm=false) const MGL_FUNC_PURE; // functions for multi-threading void pxl_pntcol(long id, long n, const void *); void pxl_combine(long id, long n, const void *); void pxl_memcpy(long id, long n, const void *); void pxl_backgr(long id, long n, const void *); void pxl_primdr(long id, long n, const void *); void pxl_dotsdr(long id, long n, const void *); void pxl_primpx(long id, long n, const void *); void pxl_transform(long id, long n, const void *); void pxl_setz(long id, long n, const void *); void pxl_setz_adv(long id, long n, const void *); void pxl_other(long id, long n, const void *p); /// Put drawing from other mglCanvas (for multithreading, like subplots) void PutDrawReg(mglDrawReg *d, const mglCanvas *gr); private: mglCanvas(const mglCanvas &){} // copying is not allowed const mglCanvas &operator=(const mglCanvas &t){return t;} // copying is not allowed uint32_t *pnt_col; // mreal _tetx,_tety,_tetz; // extra angles std::vector stack; ///< stack for transformation matrices GifFileType *gif; mreal fscl,ftet; ///< last scale and rotation for glyphs long forg; ///< original point (for directions) size_t grp_counter; ///< Counter for StartGroup(); EndGroup(); mglMatrix Bt; ///< temporary matrix for text float pen_delta; ///< delta pen width (dpw) -- the size of semi-transparent region for lines, marks, ... /// Draw generic colorbar void colorbar(HCDT v, const mreal *s, int where, mreal x, mreal y, mreal w, mreal h, bool text); /// Draw labels for ticks void DrawLabels(mglAxis &aa, bool inv=false, const mglMatrix *M=0); /// Get label style char GetLabelPos(mreal c, long kk, mglAxis &aa); /// Draw tick void tick_draw(mglPoint o, mglPoint d1, mglPoint d2, int f); mreal FindOptOrg(char dir, int ind) const MGL_FUNC_PURE; /// Transform mreal color and alpha to bits format unsigned char* col2int(const mglPnt &p, unsigned char *r, int obj_id) const; /// Combine colors in 2 plane. void combine(unsigned char *c1, const unsigned char *c2) const; /// Fast drawing of line between 2 points void fast_draw(const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d); /// Additionally scale points p for positioning in image void PostScale(const mglMatrix *M, mglPoint &p) const; /// Scale points p for projection to the face number nface in image long ProjScale(int nface, long p, bool text=false); /// Set coordinate and add the point, return its id long setPp(mglPnt &q, const mglPoint &p); // functions for glyph drawing void glyph_fill(const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d); void glyph_wire(const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d); void glyph_line(const mglMatrix *M, const mglPnt &p, mreal f, bool solid, const mglDrawReg *d); // fill pixel for given primitive void mark_pix(long i,long j,const mglPnt &p, char type, mreal size, mglDrawReg *d); void arrow_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, char st, mreal size, const mglDrawReg *d); void line_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglDrawReg *d); void trig_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, bool anorm, const mglDrawReg *d); void quad_pix(long i,long j,const mglPnt &p1, const mglPnt &p2, const mglPnt &p3, const mglPnt &p4, const mglDrawReg *d); void glyph_pix(long i,long j,const mglPrim &P, mglDrawReg *d); void pnt_pix(long i,long j,const mglPnt &p, const mglDrawReg *d); void glyph_fpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d); void glyph_wpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, const mglGlyph &g, const mglDrawReg *d); void glyph_lpix(long i,long j,const mglMatrix *M, const mglPnt &p, mreal f, bool solid, const mglDrawReg *d); }; //----------------------------------------------------------------------------- struct mglThreadG { mglCanvas *gr; // grapher void (mglCanvas::*f)(long i, long n, const void *); unsigned id; // thread id long n; // total number of iteration const void *p; // external parameter }; /// Start several thread for the task void mglStartThread(void (mglCanvas::*func)(long i, long n), mglCanvas *gr, long n); //----------------------------------------------------------------------------- #endif