You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
12 KiB

/***************************************************************************
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 <config.h>
#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