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
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|