/*************************************************************************** qsprojection.h ------------------- begin : 01-January-2000 copyright : (C) 2000 by Kamil Dobkowski email : kamildobk@poczta.onet.pl ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef QSPROJECTION_H #define QSPROJECTION_H #ifdef HAVE_CONFIG_H #include #endif #include"qscoord.h" #include"qsgattr.h" class QSAxes; /** * \brief Base class for 2D,3D world -> screen transformations. * * Transformations maps points from world coordinates ( 2d,3d space ) to * screen(canvas) coordinates and also clips polygon and lines to the viewport. Each axes object such as QSAxes2D, QSAxes3D * provides its own implementation of transformation object which can be acessed through this interface, see QSAxes::proj() * There are two sets of functions: first which maps coordinates from 2D world * to screen and the second, which maps coordinates from 3D world to screen. The first set should be used * by 2d plots and the second should be used by 3d plots. Projection can treat mappings from world2D in a * special way allowing plotting 2d datasets on a different planes etc. This will be detailed in the next version. * Notice that QSAxes2D also provides world3DToCanvas() methods allowing drawing 3D datasets on 2D axes. * Projection expect all world coordinates to be in range 0.0-1.0. * see world2DToCanvas() and world2DToCanvas3() world3DToCanvas() world3DToCanvas3() furthest() middle() * canvas3ToWorld3D() */ class QSProjection { public: /** * PI */ static const double pi; /** * Degrees to radians */ static inline double degToRad( double deg ) { return deg*pi/180.0; } /** * Radians to degrees */ static inline double radToDeg( double rad ) { return rad*180.0/pi; } /** * Clipping result. * @see #clipLine * @see #clipPoly */ enum ClipResult { Rejected = 0, Clipped, Accepted }; /** * Constructor */ QSProjection(); /** * Destructor */ virtual ~QSProjection(); /** * Turns on lighting. */ virtual void setLight( bool enabled ); /** * Sets light parameters */ virtual void setLightParameters( const QSPt3f& lightVector, int ambientLight, int directedLight ); /** * Is light turned on ? */ bool light() const { return m_light; } /** * light direction - normalized vector */ QSPt3f lightVector() const { return m_light_vector; } /** * ambient light intensity ( -50,50 ) */ int ambientLight() const { return m_ambient_light; } /** * directed light intensity ( -50, 50 ) */ int directedLight() const { return m_directed_light; } /** * Maps the point to the screen coordinates+depth. */ virtual QSPt3f world2DToCanvas3( const QSPt2f& p ) const = 0; /** * Maps the point to the screen coordinates - the same as * world2DToCanvas3() but the depth is not returned. Provided * only for efficiency. */ virtual QSPt2f world2DToCanvas( const QSPt2f& p ) const = 0; /** * Maps 'p' to the screen coordinates.+ depth */ virtual QSPt3f world3DToCanvas3( const QSPt3f &p ) const = 0; /** * Maps 'p' to the screen coordinates. - the same as * world3DToCanvas3() but the depth not returned. Provided * only for efficiency. */ virtual QSPt2f world3DToCanvas( const QSPt3f &p ) const = 0; /** * Maps 'p' from canvas coordinates to world coordinates. */ virtual QSPt3f canvas3ToWorld3D( const QSPt3f &p ) const = 0; /** * */ QSPt2f map( const QSPt3f& pos ) const { return QSPt2f( pos.x, pos.y ); } /** * */ QSPt3f map( const QSPt2f& pos ) const { return QSPt3f( pos.x, pos.y, 0.0 ); } /** * Returns a point from [(0, 0, 0) ( 1, 1, 1 )] cube, which has the greatest * z coordinate and all its three neighbourng walls are visible. * @see QSProjection3D::T */ virtual QSPt3f furthest() const; /** * Middle point */ virtual QSPt2f middle() const; /** * Tests if point is inside the clipping area. Returns 'Rejected' or 'Accepted'. */ virtual ClipResult clipPoint2( const QSPt2f& p1 ) const; /** * Clips a line defined by 'p1' and 'p2' to the clipping rectangle. * Returns a state of the operation: * 'Clipped' - the line was clipped and coordinates of points were written to 'out', * 'Rejected' - the line was thrown away ( coordinates not modified ), * 'Accepted' - the line is inside the clipping rectangle ( coordinates were not modified ). * @see #setClipRect */ virtual ClipResult clipLine2( QSPt2f* p1, QSPt2f* p2 ) const; /** This method clips a polygon defined by 'npoints' points in 'in' to the clip rectangle * and returns a new polygon in 'out'. Table 'out' must be large enough to contain all * vertices after clipping. The maximum size of this table must be given as 'maxpoints'. * If 'outedges' array is passed returns edges to be drawn ( those will be all unclipped edges ), * you can pass a table with an initial edge state in 'inedges'. * Returns a state of the operation: * 'Clipped' - the polygon was clipped and coordinates of points were written to 'out', * 'Rejected' - the polygon was thrown away ( coordinates in 'out...' were not modified ), * 'Accepted' - the polygon is inside the clipping rectangle ( coordinates in 'out...' were not modified ). * @see #setClipRect */ virtual ClipResult clipPoly2( const QSPt2f in[], int inpoints, QSPt2f out[], int *outpoints, int maxout, bool outedges[] = NULL, const bool inedges[] = NULL ) const; /** * Tests if point is inside the clipping space. Returns 'Rejected' or 'Accepted'. */ virtual ClipResult clipPoint3( const QSPt3f& pos ) const; /** * Clips line. */ virtual ClipResult clipLine3( QSPt3f* p1, QSPt3f* p2 ) const; /** * This method clips the polygon defined by 'npoints' points in 'in' to the axis box [(0,0,0),(1,1,1)] * and returns a new mesh in 'out'. Table 'out' must be large enough to contain all vertices after clipping. * The size of this table must be given in 'maxpoints'. * If 'outedges' array is passed returns edges to be drawn ( those will be all unclipped edges ), * you can pass a table with an initial edge state in 'inedges'. * Returns a state of the operation: * 'Clipped' - the polygon was clipped and coordinates of points were written to 'out', * 'Rejected' - the polygon was thrown away ( coordinates not modified ), * 'Acccepted' - the polygon is inside the axis box ( coordinates were not modified ). */ virtual ClipResult clipPoly3( const QSPt3f in[], int inpoints, QSPt3f out[], int *outpoints, int maxpoints, const QSPt3f cube[2], bool outedges[] = NULL, const bool inedges[] = NULL ) const; /** * Shades 'fill' color. */ virtual void shade( QSGFill &fill, const QSPt3f& normal, const QSPt2f* canvas_pts, int npoints, QSGFill *bottomFill ) const; //-----------------------------------------------------------------------------------------------------// /** * Tests if point 'pos' is inside polygon 'pts'. No need to reimplement. */ static bool pointInPoly( const QSPt2f& pos, const QSPt2f* pts, int npts ); //-----------------------------------------------------------------------------------------------------// /** * Returns 'p1 * p2' . */ static double dotProduct( const QSPt3f& p1, const QSPt3f& p2 ); /** * Returns 'p1 x p2' . */ static QSPt3f vectorProduct( const QSPt3f& p1, const QSPt3f& p2 ); /** * Returns the normal to the given quad. */ static QSPt3f normal( const QSPt3f vertices[4], bool normalize = true ); /** * Returns the normal to the given polygon. */ static QSPt3f normal( const QSPt3f *v, int npoints, bool normalize = true ); /** * Normalize vector. */ static QSPt3f normalize( QSPt3f vector ); /** * Calculates a bounding box of the polygon defined by 'inpoints' vertices in in[] and * writes it to the 'cube[]' table. */ static void getPoly3Cube( const QSPt3f in[], int inpoints, QSPt3f cube[2] ); /** * */ static ClipResult clipLine( QSPt2f* p0, QSPt2f* p1, const QSPt2f& clip_pos, const QSPt2f& clip_area ); /** * Calculates interpolated normals. With the given polygon defined by 'inpoint' vertices 'in[]', and normals * to those vertices in 'innors[]', calculates normals at 'clippoints' points 'clip[]' interpolating * respective normals of the polygon and writes them to 'outnors[]', which must have size equal to 'clippoints'. * All points in 'clip[]' must lie inside the given polygon. */ static void clipVertexNormals( const QSPt3f in[], int inpoints, const QSPt3f clip[], int clipoints, const QSPt3f innors[], QSPt3f outnor[] ); /** * Calculates interpolated colors. With the given polygon defined by 'inpoints' vertices 'in[]', and colors * of those vertices in 'incols[]', calculates colors at 'clippoints' points 'clip[]' interpolating * respective colors of the polygon and writes them to 'outcols[]', which must have size equal to 'clippoints'. * All points in 'clip[]' must lie inside the given polygon. */ static void clipVertexColors( const QSPt3f in[], int inpoints, const QSPt3f clip[], int clipoints, const QSGFill incol[], QSGFill outcol[] ); /** * Checks wheather a bottom side of the given polygon is visible. All points are in canvas coordinates. */ static bool isBottom( const QSPt2f pts[], int npoints ); /** * Checks wheather a bottom side of the given polygon is visible. All points are in canvas coordinates. */ static bool isBottom( const QSPt3f pts[], int npoints ); /** * The special version for triangles of the above function. All points are in canvas coordinates. */ static inline bool isBottom( const QSPt3f &p0,const QSPt3f &p1, const QSPt3f &p2 ) { return 0.0 > p2.x*p0.y - p0.x*p2.y + p0.x*p1.y - p1.x*p0.y + p1.x*p2.y - p2.x*p1.y; } /** * Triangulates the given polygon and checks if all triangles have the same side visible ( all have top or all have the bottom side visible ). All points are in canvas coordinates. */ static bool isFlat( const QSPt3f pts[], int npoints ); static bool isCorrect( const QSPt3f pts[4] ); static bool isCorrect( const double values[4] ); /* * Extracs triangle from polygon. This methods divides polygon into npoints-2 triangles. */ static void triangulate1( int triangleNumber, const QSPt3f pts[], int npoints, QSPt3f triangle[3], bool edges[3] ); protected: bool m_light; QSPt3f m_light_vector; int m_ambient_light; int m_directed_light; private: static QSPt3f interpolation( const QSPt3f& p1, const QSPt3f& p2, double t ); static QSGFill interpolation( const QSGFill& f1, const QSGFill& f2, double t ); static void get_interpolation_params(const QSPt3f in[], int inpoints, const QSPt3f& clip, int p1[2], int p2[2], double *t1, double *t2, double *t3 ); }; #endif