/****************/ /* sin.cpp */ /****************/ // Ohjelma, jolla piirretään sin x:n kuvaaja // /vl-96 // Projektiin vain tämä tiedosto. OWL 5.0 #include #include #include //------------------------------------------------------------------------------ typedef double (*tFunc)(double x); // R->R funktiotyyppi //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ class cDPoint { // Reaalilukupiste //------------------------------------------------------------------------------ double x,y; public: cDPoint (double ix=0, double iy=0) : x(ix),y(iy) {} double px() const { return x; } double py() const { return y; } }; //------------------------------------------------------------------------------ class cDRect { // Reaaliluku suorakaide; //------------------------------------------------------------------------------ cDPoint p1,p2; // Vasen alanurkka ja oikea ylänurkka public: cDRect(double x1=0,double x2=1,double y1=0,double y2=1) : p1(x1,y1),p2(x2,y2) {} cDRect(tFunc f,double x1, double x2,double dx=0) { scan(f,x1,x2,dx); } void scan(tFunc f,double x1, double x2,double dx=0); double Width() const { return p2.px() - p1.px(); } double Height() const { return p2.py() - p1.py(); } double MidX() const { return ( p1.px() + p2.px() ) / 2.0; } double MidY() const { return ( p1.py() + p2.py() ) / 2.0; } const cDPoint &rp1() const { return p1; } const cDPoint &rp2() const { return p2; } }; void cDRect::scan(tFunc f,double x1, double x2,double dx) // Alustetaan suorakaide funktion f minimillä ja maksimilla // Jos dx = 0, jaetaan väli 100 osaan { double fx,x,y1=f(x2),y2=f(x2); if ( dx == 0 ) dx = (x2-x1)/100; for ( x=x1; x x2 ) x2 = p2.px(); if ( p2.py() > y2 ) y2 = p2.py(); p1 = cDPoint(x1,y1); p2 = cDPoint(x2,y2); } //------------------------------------------------------------------------------ const int VSIZE=4; // VSIZE voi olla joko 3 (2D kuvat) tai 4 (3D kuvat) int vsize(int &i) // Pakotetaan aina i välille [0,VSIZE-1] { if ( VSIZE <= i ) i = VSIZE-1; if ( i < 0 ) i = 0; return i; } //------------------------------------------------------------------------------ class cVector { //------------------------------------------------------------------------------ protected: double a[VSIZE]; public: cVector(double a0=0.0, double a1=0.0, double a2=0.0); cVector(int i, double ai=1.0); double operator*(const cVector &b) const; // Sisätulo double operator[](int i) const { return a[vsize(i)]; } double &operator[](int i) { return a[vsize(i)]; } }; cVector::cVector(double a0, double a1, double a2) { // Alustetaan vektoriksi (a0,a1,a2,1) for (int i=0; i iRect { cTMatrix m; double scale,xs,ys,dxf,dyf,dxt,dyt; // s=scale, f=from, t=to dxf = dRect.Width(); dyf = dRect.Height(); dxt = iRect.right - iRect.left; dyt = iRect.top - iRect.bottom; if ( dxf == 0 || dxt == 0) xs = 1; else xs = dxt/dxf; if ( dyf == 0 || dyt == 0) ys = 1; else ys = dyt/dyf; if ( equal ) { // Jos halutaan x/y = 1 scale = fabs(xs); if ( fabs(ys) < scale ) scale = fabs(ys); xs = fabs(xs)/xs*scale; ys = fabs(ys)/ys*scale; } m[0][0] = xs; m[1][1] = ys; m[0][VSIZE-1] = (iRect.left+iRect.right)/2.0 - dRect.MidX()*xs; m[1][VSIZE-1] = (iRect.top+iRect.bottom)/2.0 - dRect.MidY()*ys; *this = m; } TPoint cTMatrix::operator()(double x,double y, double z) const { // Kutsulla A(x,y) muutetaan reaalimaailman piste näytön pisteeksi cVector vr(x,y,z); // Reaalimaailman vektori cVector vs(*this * vr ); // Näytöllä vastaava vektori return TPoint(int(vs[0]),int(vs[1])); } //------------------------------------------------------------------------------ class cRotMatrix : public cMatrix { // Rotaatiomatriisi //------------------------------------------------------------------------------ public: cRotMatrix(int axis,double deg); }; cRotMatrix::cRotMatrix(int axis,double deg) : cMatrix() // Kierto akselin ympäri (0=x,1=y,2=z) // 0: 1 0 0 1: c 0 -s 2: c -s 0 // 0 c -s 0 1 0 s c 0 // 0 s c s 0 c 0 0 1 { double a = deg*M_PI/180.0, ca=cos(a), sa=sin(a); int j[2]; for (int i=0,ji=0; i<3; i++) if ( i != axis ) j[ji++] = i; r[j[0]][j[0]] = ca; r[j[1]][j[1]] = ca; r[j[0]][j[1]] =-sa; r[j[1]][j[0]] =+sa; } //------------------------------------------------------------------------------ class cCoordinate { // Piirtää koordinaatiston R2:ssa //------------------------------------------------------------------------------ cDPoint origo; cDRect dRect; cDPoint ds; // small = pikkutikkujen välit cDPoint db; // big = isojen tikkujen välit const char *xformat; const char *yformat; void XTicks(TDC &dc, const cTMatrix &A,double dx, double dty) const; void YTicks(TDC &dc, const cTMatrix &A,double dy, double dtx) const; void XLabels(TDC &dc, const cTMatrix &A, double dx, double dty) const; void YLabels(TDC &dc, const cTMatrix &A, double dy, double dtx) const; public: cCoordinate() : origo(0,0), dRect(), db(1.0,1.0), ds(0.1,0.1) { xformat = "%3.1lf"; yformat = "%3.1lf"; } void SetOrigo(const cDPoint &pt) { origo = pt; } void SetRect(const cDRect rc) { dRect = rc; } void SetSmallTicks(const cDPoint &pt) { ds = pt; } void SetBigTicks(const cDPoint &pt) { db = pt; } void SetXFormat(const char *format) { xformat = format; } void SetYFormat(const char *format) { yformat = format; } void Draw(TDC &dc, const cTMatrix &A) const; }; void cCoordinate::XTicks(TDC &dc, const cTMatrix &A, double dx, double dty) const { double x,y1,y2; y1 = origo.py()-dty; y2 = origo.py()+dty; for ( x = origo.px(); x >= dRect.rp1().px(); x -= dx ) { dc.MoveTo(A(x,y1)); dc.LineTo(A(x,y2)); } for ( x = origo.px(); x <= dRect.rp2().px(); x += dx ) { dc.MoveTo(A(x,y1)); dc.LineTo(A(x,y2)); } } void cCoordinate::YTicks(TDC &dc, const cTMatrix &A, double dy, double dtx) const { double y,x1,x2; x1 = origo.px()-dtx; x2 = origo.px()+dtx; for ( y = origo.py(); y >= dRect.rp1().py(); y -= dy ) { dc.MoveTo(A(x1,y)); dc.LineTo(A(x2,y)); } for ( y = origo.py(); y <= dRect.rp2().py(); y+= dy ) { dc.MoveTo(A(x1,y)); dc.LineTo(A(x2,y)); } } void cCoordinate::XLabels(TDC &dc, const cTMatrix &A, double dx, double dty) const { if ( xformat == NULL ) return; double x,y1; char s[50]; dc.SaveDC(); dc.SetTextAlign(TA_CENTER); y1 = origo.py()-dty; for ( x = origo.px()-dx; x >= dRect.rp1().px(); x -= dx ) { sprintf(s,xformat,x); dc.TextOut(A(x,y1),s); } for ( x = origo.px()+dx; x <= dRect.rp2().px(); x += dx ) { sprintf(s,xformat,x); dc.TextOut(A(x,y1),s); } } void cCoordinate::YLabels(TDC &dc, const cTMatrix &A, double dy, double dtx) const { if ( yformat == NULL ) return; double x1,y; char s[50]; TSize size = dc.GetTextExtent("X",1); size.cx = 0; size.cy /= 2; dc.SaveDC(); dc.SetTextAlign(TA_RIGHT); x1 = origo.px()-dtx; for ( y = origo.py()-dy; y >= dRect.rp1().py(); y -= dy ) { sprintf(s,yformat,y); dc.TextOut(A(x1,y)-size,s); } for ( y = origo.py()+dy; y <= dRect.rp2().py(); y += dy ) { sprintf(s,yformat,y); dc.TextOut(A(x1,y)-size,s); } dc.RestoreDC(); } void cCoordinate::Draw(TDC &dc, const cTMatrix &A) const { dc.MoveTo(A(dRect.rp1().px(),origo.py())); dc.LineTo(A(dRect.rp2().px(),origo.py())); XTicks(dc,A,ds.px(),dRect.Height()/100); XTicks(dc,A,db.px(),dRect.Height()/40); XLabels(dc,A,db.px(),dRect.Height()/40); dc.MoveTo(A(origo.px(),dRect.rp1().py())); dc.LineTo(A(origo.px(),dRect.rp2().py())); YTicks(dc,A,ds.px(),dRect.Width()/100); YTicks(dc,A,db.px(),dRect.Width()/40); YLabels(dc,A,db.px(),dRect.Width()/30); } //------------------------------------------------------------------------------ void Draw(TDC &dc, const cTMatrix &A, tFunc f, double x1, double x2, double dx, COLORREF col=RGB(0,0,0)) //------------------------------------------------------------------------------ { dc.SaveDC(); TPen pen(col); dc.SelectObject(pen); dc.MoveTo(A(x1,f(x1))); for (double x=x1+dx; x