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.
1280 lines
38 KiB
1280 lines
38 KiB
/***************************************************************************
|
|
qsaxes3d.cpp
|
|
-------------------
|
|
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. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include"qsaxes3d.h"
|
|
#include"qsaxis.h"
|
|
#include"qsdrvopengl.h"
|
|
#include"qsdrvqt.h"
|
|
#include<assert.h>
|
|
#include<math.h>
|
|
#include<algo.h>
|
|
|
|
struct QSAxes3D::qsaxes3d_runtime_data {
|
|
QSPt3f side_norms[6];
|
|
QSGFill wall_fills[6];
|
|
QSGLine wall_lines[6];
|
|
bool v_max[4];
|
|
bool v_min[4];
|
|
bool v_fir[4];
|
|
bool v_sec[4];
|
|
bool has_grid[6][6];
|
|
bool has_grid_opposite[6][6];
|
|
};
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxes3D::QSAxes3D(QObject * parent, const char * name)
|
|
:QSAxes(parent,&t,name)
|
|
{
|
|
m_drv = NULL;
|
|
m_gl.enabled = false;
|
|
|
|
// default values
|
|
m_gl.transparency = false;
|
|
m_gl.shadewalls = true;
|
|
m_gl.autostroke = true;
|
|
m_gl.autostrokel = -45;
|
|
m_gl.globaltr = 0;
|
|
|
|
m_view.azimuth = 45;
|
|
m_view.elevation = 30;
|
|
m_view.lightAzimuth = 135;
|
|
m_view.lightElevation = 30;
|
|
|
|
m_view.distance = 0;
|
|
m_view.directLight = 0;
|
|
m_view.ambientLight = 10;
|
|
m_view.focus = 35;
|
|
|
|
m_view.perspective = false;
|
|
m_view.lighted = false;
|
|
m_view.autoscale = true;
|
|
m_is_graphics_active = false;
|
|
|
|
m_view.xEdge = 1.0;
|
|
m_view.yEdge = 1.0;
|
|
m_view.zEdge = 0.75;
|
|
|
|
m_view.xyThick = 0.05;
|
|
m_view.xzThick = 0.0;
|
|
m_view.yzThick = 0.0;
|
|
|
|
t.matrixI( t.M );
|
|
t.matrixI( t.P );
|
|
t.matrixI( t.T );
|
|
|
|
d = NULL;
|
|
|
|
#define CHANNELS_NUM 0
|
|
#define FONTS_NUM 0
|
|
#define FILLS_NUM 5
|
|
#define LINES_NUM 5
|
|
#define POINTS_NUM 0
|
|
|
|
initChannelTable( CHANNELS_NUM );
|
|
initAttributeTables( FONTS_NUM, FILLS_NUM, LINES_NUM, POINTS_NUM );
|
|
defaultSettings();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxes3D::~QSAxes3D()
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setEdgeLength( double xEdge, double yEdge, double zEdge )
|
|
{
|
|
if ( xEdge != m_view.xEdge ||
|
|
yEdge != m_view.yEdge ||
|
|
zEdge != m_view.zEdge ) {
|
|
parametersChanging();
|
|
if ( xEdge > 0.0 ) m_view.xEdge = xEdge;
|
|
if ( yEdge > 0.0 ) m_view.yEdge = yEdge;
|
|
if ( zEdge > 0.0 ) m_view.zEdge = zEdge;
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setXEdgeLength( double length )
|
|
{
|
|
if ( length > 0.0 ) {
|
|
SET_PROPERTY( m_view.xEdge, length );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setYEdgeLength( double length )
|
|
{
|
|
if ( length > 0.0 ) {
|
|
SET_PROPERTY( m_view.yEdge, length );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setZEdgeLength( double length )
|
|
{
|
|
if ( length > 0.0 ) {
|
|
SET_PROPERTY( m_view.zEdge, length );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::drawAxis( QSAxis *axis )
|
|
{
|
|
if ( axis->visible() )
|
|
if ( axis->type() == QSAxis::XAxisType ||
|
|
axis->type() == QSAxis::YAxisType ||
|
|
axis->type() == QSAxis::ZAxisType ) {
|
|
QSPt3f f = t.furthest();
|
|
QSPt3f l = t.left();
|
|
QSPt3f p1( opposite_side(f.x), opposite_side(f.y), f.z );
|
|
QSPt3f p2( opposite_side(f.x), opposite_side(f.y), f.z );
|
|
|
|
if ( axis->type() == QSAxis::ZAxisType ) p1 = p2 = QSPt3f( l.x,
|
|
l.y,
|
|
0.0 );
|
|
|
|
if ( axis->oppositePosition() ) p1 = p2 = QSPt3f( opposite_side(p1.x),
|
|
opposite_side(p1.y),
|
|
opposite_side(p1.z) );
|
|
// tic direction and length
|
|
QSPt3f d = p1 - f;
|
|
double xAxisScale;
|
|
double yAxisScale;
|
|
double zAxisScale;
|
|
double tic_len = 15.0 / 500.0;
|
|
get_axis_lengths( &xAxisScale, &yAxisScale, &zAxisScale );
|
|
switch( axis->type() ) {
|
|
case QSAxis::XAxisType: p1.x = 0.0; p2.x = 1.0; d.x = 0.0; break;
|
|
case QSAxis::YAxisType: p1.y = 0.0; p2.y = 1.0; d.y = 0.0; break;
|
|
case QSAxis::ZAxisType: p1.z = 0.0; p2.z = 1.0; d.z = 0.0; break;
|
|
}
|
|
|
|
// take care about thickness
|
|
for( int side=0; side<6; side++ ) {
|
|
if ( point_on_side(p1,side) &&
|
|
point_on_side(p2,side) &&
|
|
point_on_side( f,side) ) {
|
|
QSPt3f thick = thickness( side );
|
|
p1 = p1 + thick;
|
|
p2 = p2 + thick;
|
|
}
|
|
}
|
|
|
|
// take care about position
|
|
double pos = axis->defaultPosition() ? 0.0 : axis->position();
|
|
p1 = p1 + QSPt3f( d.x*pos, d.y*pos, d.z*pos );
|
|
p2 = p2 + QSPt3f( d.x*pos, d.y*pos, d.z*pos );
|
|
|
|
// draw axis line
|
|
m_drv->setLine( axis->line(QSAxis::AxisLine) );
|
|
if ( axis->reversed() ) m_drv->drawArrow( t.world3DToCanvas(p2), t.world3DToCanvas(p1), axis->arrow1(), axis->arrow2() );
|
|
else m_drv->drawArrow( t.world3DToCanvas(p1), t.world3DToCanvas(p2), axis->arrow1(), axis->arrow2() );
|
|
|
|
// draw tics and labels
|
|
int tic_nr = 0;
|
|
m_drv->setCurrentElement( QSAxes::GridCategory, axisIndex(axis) );
|
|
QSGLine tic_line = axis->line(QSAxis::AxisLine); tic_line.style = QSGLine::Solid;
|
|
list<QSAxisTic>::const_iterator curr = axis->tics()->begin();
|
|
list<QSAxisTic>::const_iterator last = axis->tics()->end();
|
|
if ( !m_really_fast ) // a little hack for paintSkeleton
|
|
while ( curr != last ) {
|
|
if ( curr->m_major ) {
|
|
switch( axis->type() ) {
|
|
case QSAxis::XAxisType: p1.x = curr->m_pos; break;
|
|
case QSAxis::YAxisType: p1.y = curr->m_pos; break;
|
|
case QSAxis::ZAxisType: p1.z = curr->m_pos; break;
|
|
}
|
|
|
|
p2 = p1 + QSPt3f( d.x*tic_len/xAxisScale, d.y*tic_len/yAxisScale, d.z*tic_len );
|
|
if ( axis->ticsVisible() ) {
|
|
m_drv->setLine( tic_line );
|
|
draw_line( p1, p2 );
|
|
}
|
|
|
|
double tic_shift = (tic_nr%2) ? axis->ticLabelPos2() : axis->ticLabelPos1();
|
|
p2 = p2 + QSPt3f( tic_shift*d.x, tic_shift*d.y, tic_shift*d.z );
|
|
m_drv->setFont( curr->m_font );
|
|
m_drv->drawRTextBox( t.world3DToCanvas(p2), curr->m_angle, curr->m_label, get_label_align(p1,p2,axis->type()) );
|
|
tic_nr++;
|
|
}
|
|
curr++;
|
|
}
|
|
|
|
// draw title
|
|
m_drv->setFont( axis->font(QSAxis::TitleFont) );
|
|
m_drv->setCurrentElement( QSAxes::AxisCategory, axisIndex(axis) );
|
|
switch( axis->type() ) {
|
|
case QSAxis::XAxisType: p1.x = axis->titlePosition(); break;
|
|
case QSAxis::YAxisType: p1.y = axis->titlePosition(); break;
|
|
case QSAxis::ZAxisType: p1.z = axis->titlePosition(); break;
|
|
}
|
|
p2 = p1 + QSPt3f( axis->titleDistance()*d.x*4.0,
|
|
axis->titleDistance()*d.y*4.0,
|
|
axis->titleDistance()*d.z*4.0 );
|
|
m_drv->drawText3( p2, axis->title(), get_label_align(p1,p2,axis->type()) );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSAxes3D::point_on_side( const QSPt3f& p, int side )
|
|
{
|
|
QSPt3f p1( 0.0, 0.0, 0.0 );
|
|
QSPt3f p2( 1.0, 1.0, 1.0 );
|
|
QSPt3f pts[4];
|
|
QSPt3f norm[5];
|
|
get_side_wall( p1, p2, side, pts, norm );
|
|
for( int i=0; i<4; i++ ) if ( pts[i] == p ) return true;
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::drawGrid( QSAxis *axis, bool major )
|
|
{
|
|
QSPt3f p1;
|
|
QSPt3f p2;
|
|
bool wall_visible;
|
|
|
|
QSPt3f pts[4];
|
|
QSPt3f norm[5];
|
|
|
|
if ( axis->visible() )
|
|
if ( axis->type() == QSAxis::XAxisType ||
|
|
axis->type() == QSAxis::YAxisType ||
|
|
axis->type() == QSAxis::ZAxisType )
|
|
for( int wall=0; wall<6; wall++ ) {
|
|
get_axis_wall( wall, &p1, &p2, &wall_visible );
|
|
|
|
bool has_grid = false;
|
|
if ( axis->oppositePosition() ) has_grid = d->has_grid_opposite[axis->type()][wall];
|
|
else has_grid = d->has_grid[axis->type()][wall];
|
|
|
|
// draw thick wall side by side
|
|
if ( has_grid && wall_visible )
|
|
for( int side=0; side<6; side++ ) {
|
|
get_side_wall( p1, p2, side, pts, norm );
|
|
if ( visible(pts[0],norm[0]) ) draw_grid( axis, major, pts, norm );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::draw_grid( QSAxis *axis, bool major, QSPt3f pts[4], QSPt3f norm[5] )
|
|
{
|
|
QSPt3f p1 = pts[0];
|
|
QSPt3f p2 = pts[2];
|
|
switch( axis->type() ) {
|
|
case QSAxis::XAxisType: if ( p1.x == p2.x || ( p1.y == p2.y && p1.z == p2.z ) ) return; break;
|
|
case QSAxis::YAxisType: if ( p1.y == p2.y || ( p1.x == p2.x && p1.z == p2.z ) ) return; break;
|
|
case QSAxis::ZAxisType: if ( p1.z == p2.z || ( p1.x == p2.z && p1.y == p2.y ) ) return; break;
|
|
}
|
|
list<QSAxisTic>::const_iterator curr = axis->tics()->begin();
|
|
list<QSAxisTic>::const_iterator last = axis->tics()->end();
|
|
while ( curr != last ) {
|
|
if ( curr->m_major == major ) {
|
|
QSPt3f p[2];
|
|
p[0] = pts[0];
|
|
p[1] = pts[2];
|
|
switch( axis->type() ) {
|
|
case QSAxis::XAxisType: p[0].x = p[1].x = curr->m_pos; break;
|
|
case QSAxis::YAxisType: p[0].y = p[1].y = curr->m_pos; break;
|
|
case QSAxis::ZAxisType: p[0].z = p[1].z = curr->m_pos; break;
|
|
}
|
|
|
|
QSPt3f n[2];
|
|
t.clipVertexNormals( pts, 4, p, 2, &norm[1], n );
|
|
m_drv->setLine( curr->m_line );
|
|
draw_line( p[0], p[1], n );
|
|
}
|
|
curr++;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::get_side_wall( const QSPt3f& p1, const QSPt3f& p2, int side_nr, QSPt3f result_pts[4], QSPt3f result_norm[5] )
|
|
// return a side wall parameters of a cube defined by p1, p2
|
|
{
|
|
result_norm[0] = d->side_norms[side_nr];
|
|
|
|
QSPt3f min( QMIN(p1.x,p2.x), QMIN(p1.y,p2.y), QMIN(p1.z,p2.z) );
|
|
QSPt3f max( QMAX(p1.x,p2.x), QMAX(p1.y,p2.y), QMAX(p1.z,p2.z) );
|
|
|
|
// make sure that all vertices are ordered in CW direction
|
|
bool *v_fir = d->v_fir;
|
|
bool *v_sec = d->v_sec;
|
|
if ( side_nr == 0 || side_nr == 3 || side_nr == 4 ) { v_fir = d->v_sec; v_sec = d->v_fir; }
|
|
|
|
// one should point to v_min or v_max, another one to v_fir, and another to v_sec
|
|
bool *v_x = result_norm[0].x<0.0 ? d->v_min : ( result_norm[0].x>0.0 ? d->v_max : v_fir );
|
|
bool *v_y = result_norm[0].y<0.0 ? d->v_min : ( result_norm[0].y>0.0 ? d->v_max : v_fir );
|
|
bool *v_z = result_norm[0].z<0.0 ? d->v_min : ( result_norm[0].z>0.0 ? d->v_max : v_sec );
|
|
if ( v_x == v_y ) v_y = v_sec;
|
|
for( int i=0; i<4; i++ ) {
|
|
if ( v_x[i] ) result_pts[i].x = max.x; else result_pts[i].x = min.x;
|
|
if ( v_y[i] ) result_pts[i].y = max.y; else result_pts[i].y = min.y;
|
|
if ( v_z[i] ) result_pts[i].z = max.z; else result_pts[i].z = min.z;
|
|
}
|
|
|
|
// normal to vertices
|
|
for( int i=1; i<5; i++ ) {
|
|
result_norm[i] = result_norm[0];
|
|
|
|
// modified for a better look
|
|
if ( result_norm[i].x == 0.0 ) result_norm[i].x = result_pts[i-1].x == max.x ? 0.3 : -0.3;
|
|
if ( result_norm[i].y == 0.0 ) result_norm[i].y = result_pts[i-1].y == max.y ? 0.3 : -0.3;
|
|
if ( result_norm[i].z == 0.0 ) result_norm[i].z = result_pts[i-1].z == max.z ? 0.3 : -0.3;
|
|
result_norm[i] = t.normalize( result_norm[i] );
|
|
}
|
|
}
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::get_axis_wall( int wall_nr, QSPt3f *result_p1, QSPt3f *result_p2, bool *visible )
|
|
{
|
|
QSPt3f p1( 0.0, 0.0, 0.0 );
|
|
QSPt3f p2( 1.0, 1.0, 1.0 );
|
|
QSPt3f pts[4];
|
|
QSPt3f norm[5];
|
|
get_side_wall( p1, p2, wall_nr, pts, norm );
|
|
|
|
// draw only rear walls
|
|
QSPt3f f = t.furthest();
|
|
*visible = false; for ( int i=0; i<4; i++ ) if ( pts[i] == f ) *visible = true;
|
|
|
|
*result_p1 = pts[0];
|
|
*result_p2 = pts[2] + thickness( wall_nr );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt3f QSAxes3D::thickness( int wall_nr )
|
|
{
|
|
QSPt3f p1( 0.0, 0.0, 0.0 );
|
|
QSPt3f p2( 1.0, 1.0, 1.0 );
|
|
QSPt3f pts[4];
|
|
QSPt3f norm[5];
|
|
get_side_wall( p1, p2, wall_nr, pts, norm );
|
|
return QSPt3f( norm[0].x*m_view.yzThick,
|
|
norm[0].y*m_view.xzThick,
|
|
norm[0].z*m_view.xyThick );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSAxes3D::visible( const QSPt3f& p, const QSPt3f& norm )
|
|
{
|
|
if ( perspective() ) t.dvector = p - t.eye;
|
|
return ( t.dotProduct(norm,t.dvector) <= 0.0 );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::draw_line( QSPt3f p1, QSPt3f p2, QSPt3f *normals )
|
|
{
|
|
QSPt3f enormals[2];
|
|
m_drv->drawLine3( p1, p2, normals ? normals : enormals );
|
|
}
|
|
//-------------------------------------------------------------//
|
|
|
|
double QSAxes3D::opposite_side( double value )
|
|
{
|
|
return value < 0.5 ? 1.0 : 0.0;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::allocRuntimeData()
|
|
{
|
|
QSAxes::allocRuntimeData();
|
|
d = new qsaxes3d_runtime_data();
|
|
d->side_norms[0] = QSPt3f( 0.0, 0.0, -1.0 ); // min xy
|
|
d->side_norms[1] = QSPt3f( 0.0, 0.0, 1.0 ); // max xy
|
|
d->side_norms[2] = QSPt3f( 0.0, -1.0, 0.0 ); // min xz
|
|
d->side_norms[3] = QSPt3f( 0.0, 1.0, 0.0 ); // max xz
|
|
d->side_norms[4] = QSPt3f( -1.0, 0.0, 0.0 ); // min yz
|
|
d->side_norms[5] = QSPt3f( 1.0, 0.0, 0.0 ); // max yz
|
|
|
|
bool v_max[4] = { true, true, true, true };
|
|
bool v_min[4] = { false, false, false, false };
|
|
bool v_fir[4] = { false, false, true, true };
|
|
bool v_sec[4] = { false, true, true, false };
|
|
|
|
for( int i=0; i<4; i++ ) {
|
|
d->v_max[i] = v_max[i];
|
|
d->v_min[i] = v_min[i];
|
|
d->v_fir[i] = v_fir[i];
|
|
d->v_sec[i] = v_sec[i];
|
|
}
|
|
|
|
d->wall_fills[0] = fill( XYWallFill );
|
|
d->wall_fills[1] = fill( XYWallFill );
|
|
d->wall_fills[2] = fill( XZWallFill );
|
|
d->wall_fills[3] = fill( XZWallFill );
|
|
d->wall_fills[4] = fill( YZWallFill );
|
|
d->wall_fills[5] = fill( YZWallFill );
|
|
|
|
d->wall_lines[0] = line( XYWallLine );
|
|
d->wall_lines[1] = line( XYWallLine );
|
|
d->wall_lines[2] = line( XZWallLine );
|
|
d->wall_lines[3] = line( XZWallLine );
|
|
d->wall_lines[4] = line( YZWallLine );
|
|
d->wall_lines[5] = line( YZWallLine );
|
|
|
|
for( int i=0; i<6; i++ )
|
|
for( int j=0; j<6; j++ ) {
|
|
d->has_grid[i][j] = false;
|
|
d->has_grid_opposite[i][j] = false;
|
|
}
|
|
d->has_grid[QSAxis::XAxisType][0] = true;
|
|
d->has_grid[QSAxis::XAxisType][1] = true;
|
|
d->has_grid[QSAxis::YAxisType][0] = true;
|
|
d->has_grid[QSAxis::YAxisType][1] = true;
|
|
d->has_grid[QSAxis::ZAxisType][2] = true;
|
|
d->has_grid[QSAxis::ZAxisType][3] = true;
|
|
d->has_grid[QSAxis::ZAxisType][4] = true;
|
|
d->has_grid[QSAxis::ZAxisType][5] = true;
|
|
|
|
d->has_grid_opposite[QSAxis::XAxisType][2] = true;
|
|
d->has_grid_opposite[QSAxis::XAxisType][3] = true;
|
|
d->has_grid_opposite[QSAxis::YAxisType][4] = true;
|
|
d->has_grid_opposite[QSAxis::YAxisType][5] = true;
|
|
d->has_grid_opposite[QSAxis::ZAxisType][2] = true;
|
|
d->has_grid_opposite[QSAxis::ZAxisType][3] = true;
|
|
d->has_grid_opposite[QSAxis::ZAxisType][4] = true;
|
|
d->has_grid_opposite[QSAxis::ZAxisType][5] = true;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::freeRuntimeData()
|
|
{
|
|
delete d; d = NULL;
|
|
QSAxes::freeRuntimeData();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::stop()
|
|
// stop drawing now.
|
|
// Clean-up
|
|
{
|
|
if ( m_is_graphics_active ) {
|
|
m_is_graphics_active = false;
|
|
m_drv->stopDrawing();
|
|
}
|
|
QSAxes::stop();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::axisRangesCalculated()
|
|
{
|
|
assert( m_drv );
|
|
init_3dtr();
|
|
assert( !m_is_graphics_active );
|
|
m_is_graphics_active = true;
|
|
m_drv->startDrawing();
|
|
|
|
//QSGFill f = background();
|
|
//if ( !m_transparent && f.style == QSGFill::Transparent ) f = QSGFill();
|
|
m_drv->clearCanvas( background(), QSPt2f( m_cpos.x, m_cpos.y ), QSPt2f( m_csize.x, m_csize.y ) );
|
|
m_drv->setTopBottom( false );
|
|
m_cnormals = m_drv->cNormals();
|
|
m_ccolors = m_drv->cColors();
|
|
m_corder = m_drv->cOrdering();
|
|
if ( m_cnormals == QSDrv::NoNormals && m_view.lighted ) m_cnormals = QSDrv::MeshNormal;
|
|
//drawAxes( 1 );
|
|
draw_box();
|
|
if ( m_axes_only ) draw_arrow();
|
|
QSAxes::axisRangesCalculated();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
// cout << " norm " << norm[0].x << ","<< norm[0].y << "," << norm[0].z << endl;
|
|
void QSAxes3D::draw_box()
|
|
{
|
|
QSPt3f p1;
|
|
QSPt3f p2;
|
|
bool wall_visible;
|
|
QSPt3f pts[4];
|
|
QSPt3f norm[5];
|
|
QSGFill fills[4];
|
|
|
|
for( int wall=0; wall<6; wall++ ) {
|
|
get_axis_wall( wall, &p1, &p2, &wall_visible );
|
|
if ( wall_visible ) {
|
|
for( int i=0; i<4; i++ ) fills[i] = d->wall_fills[wall];
|
|
m_drv->setLine( d->wall_lines[wall] );
|
|
m_drv->setFill( d->wall_fills[wall] );
|
|
|
|
// draw thick wall side by side
|
|
for( int side=0; side<6; side++ ) {
|
|
get_side_wall( p1, p2, side, pts, norm );
|
|
if ( visible(pts[0],norm[0]) ) m_drv->drawPoly3( pts, 4, norm, fills );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::paintPlot( QPainter *paint, double dpi, bool blocking, bool transparent )
|
|
{
|
|
if ( paint )
|
|
#ifdef HAVE_GL
|
|
if ( m_gl.enabled ) {
|
|
if ( m_internal_state == Busy ) stop();
|
|
QSDrvOpenGL gl_drv;
|
|
gl_drv.setAlpha( m_gl.transparency );
|
|
gl_drv.setShadeWalls( m_gl.shadewalls );
|
|
gl_drv.setGlobalTransparency( m_gl.globaltr );
|
|
gl_drv.setMeshAutoStroke( m_gl.autostroke );
|
|
gl_drv.setAutoStrokeLightness( m_gl.autostrokel );
|
|
gl_drv.setProjection( &t );
|
|
gl_drv.setDC( paint, dpi, false );
|
|
gl_drv.init( this );
|
|
start( &gl_drv, blocking, transparent );
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if ( m_internal_state == Busy ) stop();
|
|
QSDrvQt qt_drv;
|
|
qt_drv.setProjection( &t );
|
|
qt_drv.setDC(paint,dpi,false); // do not delete QPainter
|
|
start( &qt_drv, blocking, transparent );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::paintSkeleton( QPainter *p, double dpi, bool reallyFast )
|
|
{
|
|
bool prev_gl = m_gl.enabled;
|
|
m_gl.enabled = false;
|
|
QSAxes::paintSkeleton( p, dpi, reallyFast );
|
|
m_gl.enabled = prev_gl;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::drawPlot( QSDrv *init_drv, bool blocking, bool transparent )
|
|
{
|
|
if ( init_drv ) {
|
|
if ( m_internal_state == Busy ) stop();
|
|
init_drv->setProjection( &t );
|
|
start( init_drv, blocking, transparent );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
#define EPS 1e-5
|
|
|
|
int QSAxes3D::get_label_align( const QSPt3f& p1, const QSPt3f& p2, int axis )
|
|
{
|
|
int halign = AlignHCenter;
|
|
int valign = AlignVCenter;
|
|
QSPt2f c1 = t.world3DToCanvas( p1 );
|
|
QSPt2f c2 = t.world3DToCanvas( p2 );
|
|
if ( c2.x - c1.x > EPS ) halign = AlignLeft;
|
|
if ( c2.x - c1.x < -EPS ) halign = AlignRight;
|
|
if ( c2.y - c1.y > EPS ) valign = AlignTop;
|
|
if ( c2.y - c1.y < -EPS ) valign = AlignBottom;
|
|
|
|
|
|
// Opps ! Corrrect this by hand
|
|
switch( axis ) {
|
|
case QSAxis::XAxisType:
|
|
case QSAxis::YAxisType: if ( valign == AlignVCenter ) valign = AlignTop; break;
|
|
case QSAxis::ZAxisType: valign = AlignVCenter; break;
|
|
}
|
|
|
|
return halign | valign;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
|
|
|
|
void QSAxes3D::setOpenGL( bool enabled )
|
|
{
|
|
SET_PROPERTY(m_gl.enabled,enabled);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setAzimuth( int angle )
|
|
{
|
|
angle = angle % 360;
|
|
if ( angle < 0 ) angle += 360;
|
|
SET_PROPERTY(m_view.azimuth,angle);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setElevation( int angle )
|
|
{
|
|
if ( angle > 90 ) angle = 90;
|
|
if ( angle < -90 ) angle = -90;
|
|
SET_PROPERTY(m_view.elevation,angle);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setFocusDistance( int d )
|
|
{
|
|
d = d % 51;
|
|
SET_PROPERTY( m_view.focus, d );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setDistance( int d )
|
|
{
|
|
d = d % 51;
|
|
SET_PROPERTY( m_view.distance, d );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setLightAzimuth( int angle )
|
|
{
|
|
angle = angle % 360;
|
|
if ( angle < 0 ) angle += 360;
|
|
SET_PROPERTY( m_view.lightAzimuth, angle );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setLightElevation( int angle )
|
|
{
|
|
if ( angle > 90 ) angle = 90;
|
|
if ( angle < -90 ) angle = -90;
|
|
SET_PROPERTY( m_view.lightElevation, angle );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setDirectLight( int lightness )
|
|
{
|
|
lightness = lightness % 51;
|
|
SET_PROPERTY( m_view.directLight, lightness );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setAmbientLight( int lightness )
|
|
{
|
|
lightness = lightness % 51;
|
|
SET_PROPERTY( m_view.ambientLight, lightness );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setLight( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_view.lighted, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setPerspective( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_view.perspective, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setAutoscale( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_view.autoscale, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setWallThickness( double xy, double xz, double yz )
|
|
{
|
|
if ( xy != m_view.xyThick ||
|
|
xz != m_view.xzThick ||
|
|
yz != m_view.yzThick ) {
|
|
parametersChanging();
|
|
if ( xy >= 0.0 ) m_view.xyThick = xy;
|
|
if ( xz >= 0.0 ) m_view.xzThick = xz;
|
|
if ( yz >= 0.0 ) m_view.yzThick = yz;
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setXYWallThickness( double thickness )
|
|
{
|
|
if ( thickness > 0.0 ) {
|
|
SET_PROPERTY( m_view.xyThick, thickness );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setXZWallThickness( double thickness )
|
|
{
|
|
if ( thickness > 0.0 ) {
|
|
SET_PROPERTY( m_view.xzThick, thickness );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::setYZWallThickness( double thickness )
|
|
{
|
|
if ( thickness > 0.0 ) {
|
|
SET_PROPERTY( m_view.yzThick, thickness );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::glSetTransparency( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_gl.transparency, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::glSetGlobalTransparency( int value )
|
|
{
|
|
SET_PROPERTY( m_gl.globaltr, value );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::glSetShadeWalls( bool enable )
|
|
{
|
|
SET_PROPERTY( m_gl.shadewalls, enable );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::glSetMeshAutoStroke( bool enable )
|
|
{
|
|
SET_PROPERTY( m_gl.autostroke, enable );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::glSetAutoStrokeLightness( int value )
|
|
{
|
|
SET_PROPERTY( m_gl.autostrokel, value );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
|
|
void QSAxes3D::defaultSettings()
|
|
{
|
|
QSGColor c;
|
|
QSGLine line;
|
|
QSGFill fill;
|
|
|
|
line.style = QSGLine::Solid;
|
|
line.color = c.set( 96, 96, 96 );
|
|
m_settings.lines[XYWallLine] = line;
|
|
m_settings.lines[XZWallLine] = line;
|
|
m_settings.lines[YZWallLine] = line;
|
|
|
|
fill.color = c.set( 224, 224, 224 );
|
|
m_settings.fills[XYWallFill] = fill;
|
|
fill.color = c.set( 240, 240, 240 );
|
|
m_settings.fills[XZWallFill] = fill;
|
|
m_settings.fills[YZWallFill] = fill;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::draw_arrow()
|
|
{
|
|
QSGLine l;
|
|
m_drv->setLine( l );
|
|
|
|
double xlen;
|
|
double ylen;
|
|
double zlen;
|
|
|
|
get_axis_lengths( &xlen, &ylen, &zlen );
|
|
|
|
double m[4][4];
|
|
|
|
t.matrixI( m );
|
|
|
|
t.applyR( m,
|
|
0.0,
|
|
m_view.lightElevation );
|
|
|
|
t.applyR( m,
|
|
0.0,
|
|
0.0,
|
|
-m_view.lightAzimuth);
|
|
|
|
t.applyS( m,
|
|
1.0/xlen,
|
|
1.0/ylen,
|
|
1.0/zlen );
|
|
|
|
t.applyS( m, 0.5, 0.5, 0.5 );
|
|
t.applyT( m, 0.5, 0.5, 0.5 );
|
|
|
|
QSPt3f p1;
|
|
QSPt3f p2;
|
|
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 0.0, 0.0 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 0.5, 0.5 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 0.5, 0.5 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 0.5, 0.17 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 0.5, 0.17 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 1.0, 0.17 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 1.0, 0.17 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 1.0, -0.17 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 1.0, -0.17 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 0.5, -0.17 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 0.5, -0.17 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 0.5, -0.5 ) ) );
|
|
draw_line( t.worldTransformation( m, p1.set( 0.0, 0.5, -0.5 ) ),
|
|
t.worldTransformation( m, p2.set( 0.0, 0.0, 0.0 ) ) );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::get_cube_min_max( QSPt3f* min, QSPt3f *max )
|
|
{
|
|
min->set( 0.0, 0.0, 0.0 );
|
|
max->set( 1.0, 1.0, 1.0 );
|
|
for( int wall=0; wall<6; wall++ ) {
|
|
QSPt3f p1, p2;
|
|
bool visible;
|
|
get_axis_wall( wall, &p1, &p2, &visible );
|
|
if ( visible ) {
|
|
min->set( QMIN(min->x,p1.x), QMIN(min->y,p1.y), QMIN(min->z,p1.z) );
|
|
min->set( QMIN(min->x,p2.x), QMIN(min->y,p2.y), QMIN(min->z,p2.z) );
|
|
max->set( QMAX(max->x,p1.x), QMAX(max->y,p1.y), QMAX(max->z,p1.z) );
|
|
max->set( QMAX(max->x,p2.x), QMAX(max->y,p2.y), QMAX(max->z,p2.z) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::init_3dtr()
|
|
{
|
|
//
|
|
// Scale, transform and fit (1,1,1) cube
|
|
// y
|
|
// ^ / z
|
|
// | /
|
|
// --->x
|
|
|
|
// transformation matrix
|
|
t.matrixI( t.M );
|
|
t.matrixI( t.P );
|
|
t.matrixI( t.T );
|
|
|
|
// make the z axis vertical
|
|
t.applyR( t.M, 0.0, -90.0 );
|
|
|
|
// shift to the middle
|
|
t.applyT( t.M, -0.5, -0.5, 0.5 );
|
|
|
|
// apply lengths set by user
|
|
double xAxisScale;
|
|
double yAxisScale;
|
|
double zAxisScale;
|
|
|
|
get_axis_lengths( &xAxisScale,
|
|
&yAxisScale,
|
|
&zAxisScale );
|
|
|
|
t.applyS( t.M,
|
|
xAxisScale,
|
|
zAxisScale,
|
|
yAxisScale );
|
|
|
|
QSPt3f cmin;
|
|
QSPt3f cmax;
|
|
get_cube_min_max( &cmin, &cmax );
|
|
double xlen = (cmax.x-cmin.x)*xAxisScale;
|
|
double ylen = (cmax.y-cmin.y)*yAxisScale;
|
|
double zlen = (cmax.z-cmin.z)*zAxisScale;
|
|
|
|
// translate to make sure that all coordinates have
|
|
// z value lower than 0 ( see focus ).
|
|
double max_diagonal = sqrt( xlen*xlen + ylen*ylen + zlen*zlen ) / 2.0;
|
|
|
|
// focus distance from 0 ( 1/101 ) to inf ( 101/1 )
|
|
// normalize to max_diagonal
|
|
double focus = (51.0+focusDistance()) /
|
|
(51.0-focusDistance()) *
|
|
max_diagonal;
|
|
|
|
double x1 = -1;
|
|
double x2 = 1;
|
|
double y1 = -1;
|
|
double y2 = 1;
|
|
double z1 = focus;
|
|
double z2 = focus+3*max_diagonal;
|
|
|
|
if ( perspective() ) {
|
|
t.frustum( t.P, x1, x2, y1, y2, z1, z2 );
|
|
t.setProjection( x1, x2, y1, y2, z1, z2, true );
|
|
} else {
|
|
t.ortho( t.P, x1, x2, y1, y2, z1, z2 );
|
|
t.setProjection( x1, x2, y1, y2, z1, z2, false );
|
|
}
|
|
|
|
// Scalling matrix. Because I don't know how to deal with frustums,
|
|
// wanting to fit axes to a view volume I always scale and fit to
|
|
// the cube. I apply modelview matrix, next
|
|
// projection matrix ( transforming frustrum into a cube ), fit to
|
|
// the cube and next apply the inversed projection matrix ( back to frustum ). .
|
|
// resulting modelview = M*P*S*P-1, resulting projection=P
|
|
// overall transform M*P*S*P-1*P = M*P*S
|
|
QSProjection3D::Matrix S;
|
|
t.matrixI( S );
|
|
if ( autoscale() ) {
|
|
|
|
t.applyR( t.M,
|
|
-azimuth(),
|
|
0.0 );
|
|
|
|
t.applyR( t.M,
|
|
0.0,
|
|
elevation() );
|
|
|
|
t.applyT( t.M,
|
|
0.0,
|
|
0.0,
|
|
-focus-1.01*max_diagonal ); // round-off errors
|
|
|
|
// transformation needs min and max coordinates
|
|
// of an axis box to be set ( for autoscaling etc. )
|
|
get_cube_min_max( &t.bmin, &t.bmax );
|
|
|
|
// autoscale
|
|
t.fit( S );
|
|
|
|
} else {
|
|
|
|
// fit to screen only when graph is in arbitrary choosen positions.
|
|
QSProjection3D::Matrix oM;
|
|
|
|
t.copy( oM, t.M );
|
|
|
|
double angle1 = t.radToDeg(atan(yAxisScale/xAxisScale));
|
|
double angle2 = t.radToDeg(atan( sqrt(xAxisScale*xAxisScale+
|
|
yAxisScale*yAxisScale) /
|
|
zAxisScale ));
|
|
|
|
// check a scale ratio at the first position
|
|
t.applyR( t.M,
|
|
angle1,
|
|
angle2 );
|
|
|
|
t.applyT( t.M,
|
|
0.0,
|
|
0.0,
|
|
-focus-max_diagonal );
|
|
|
|
QSProjection3D::Matrix S1;
|
|
t.fit( S1 );
|
|
|
|
// the second position
|
|
t.copy( t.M, oM );
|
|
|
|
t.applyR( t.M,
|
|
angle1,
|
|
90.0 );
|
|
|
|
t.applyT( t.M,
|
|
0.0,
|
|
0.0,
|
|
-focus-1.01*max_diagonal ); // round-off errors
|
|
|
|
QSProjection3D::Matrix S2;
|
|
t.fit( S2 );
|
|
|
|
// apply a smaller scale ratio
|
|
if ( S1[0][0] < S2[0][0] ) t.copy( S, S1 );
|
|
else t.copy( S, S2 );
|
|
|
|
// viewpoint
|
|
t.copy( t.M, oM );
|
|
|
|
t.applyR( t.M,
|
|
-azimuth(),
|
|
0.0 );
|
|
|
|
t.applyR( t.M,
|
|
0.0,
|
|
elevation() );
|
|
|
|
t.applyT( t.M,
|
|
0.0,
|
|
0.0,
|
|
-focus-max_diagonal );
|
|
|
|
// transformation needs min and max coordinates
|
|
// of an axis box to be set
|
|
get_cube_min_max( &t.bmin, &t.bmax );
|
|
}
|
|
|
|
// Scale set by user
|
|
double scale = (distance()+50.0)/50.0;
|
|
// tics not working well ( something wrong with drawLine in OpenGL
|
|
// when line starts at the border of the view volume )
|
|
if ( scale == 1.0 ) scale = 0.99;
|
|
t.applyS( S, scale, scale, 1.0 );
|
|
//cout << " S MATRIX " << endl;
|
|
//QSProjection3D::matrix_to_stdout( S );
|
|
//cout << endl;
|
|
|
|
// incorporate scale matrix in M matrix
|
|
QSProjection3D::Matrix P1;
|
|
t.inv( P1, t.P );
|
|
|
|
QSProjection3D::Matrix SCALE;
|
|
t.matrixI( SCALE );
|
|
t.multiply( SCALE, t.P );
|
|
t.multiply( SCALE, S );
|
|
t.multiply( SCALE, P1 );
|
|
//cout << " SCALE MATRIX " << endl;
|
|
//QSProjection3D::matrix_to_stdout( SCALE );
|
|
//cout << endl;
|
|
|
|
t.multiply( t.M, SCALE );
|
|
|
|
// make a general transformation matrix
|
|
t.copy( t.T, t.M );
|
|
t.multiply( t.T, t.P );
|
|
|
|
// 0, 0 in the top-left corner
|
|
t.applyS( t.T, 1.0, -1.0, 1.0 );
|
|
|
|
// apply ( and remember ) the viewport transformation
|
|
t.applyViewport( t.T, m_cpos.x, m_cpos.y, m_csize.x, m_csize.y );
|
|
t.setViewport( m_cpos.x, m_cpos.y, m_csize.x, m_csize.y );
|
|
|
|
//
|
|
// focus vector ( top/bottom detection )
|
|
//
|
|
QSPt3f p; QSProjection3D::Matrix temp;
|
|
|
|
t.inv( temp, t.M );
|
|
t.eye = t.worldTransformation(temp, p.set(0.0,0.0,0.0));
|
|
|
|
if ( !perspective() )
|
|
t.dvector = t.normalize( t.worldTransformation( temp, p.set(0.0, 0.0, -1.0) ) - t.eye );
|
|
else
|
|
t.dvector = QSPt3f( 0.0, 0.0, 0.0 );
|
|
|
|
t.multiply( temp, t.M );
|
|
|
|
//-----------------------//
|
|
|
|
//
|
|
// light vector in 3D world coordinates
|
|
//
|
|
t.matrixI( temp );
|
|
|
|
t.applyR( temp,
|
|
0.0,
|
|
lightElevation() );
|
|
|
|
t.applyR( temp,
|
|
0.0,
|
|
0.0,
|
|
-lightAzimuth() );
|
|
|
|
t.applyS( temp,
|
|
1.0/xAxisScale,
|
|
1.0/yAxisScale,
|
|
1.0/zAxisScale );
|
|
|
|
t.lvector = t.normalize( t.worldTransformation(temp, p.set(0.0, 1.0, 0.0)) );
|
|
|
|
t.setLight( light() );
|
|
t.setLightParameters( t.lvector, ambientLight(), directLight() );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::get_axis_lengths( double *x, double *y, double *z )
|
|
// see set..AxisLength()
|
|
{
|
|
double xlen = m_view.xEdge;
|
|
double ylen = m_view.yEdge;
|
|
double zlen = m_view.zEdge;
|
|
|
|
double min_len = min(min(xlen,ylen),zlen);
|
|
if ( x ) *x = xlen/min_len;
|
|
if ( y ) *y = ylen/min_len;
|
|
if ( z ) *z = zlen/min_len;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::initMappings( QSDrv *m_drv )
|
|
{
|
|
QSAxes::initMappings( m_drv );
|
|
if ( !state() ) {
|
|
allocRuntimeData();
|
|
init_3dtr();
|
|
freeRuntimeData();
|
|
m_drv->startDrawing();
|
|
m_drv->stopDrawing();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt3f QSAxes3D::mixedToCanvas( const QSPt3f& pos, CoordinateSystem in_coords[3], double dpi, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const
|
|
// doesn't check if coordinates are right
|
|
// if there is at least one dataCoord or worldCoord all remaining normCoords and mmCoord are treaten as worldCoord
|
|
{
|
|
bool is_3d = false;
|
|
QSPt3f result = pos;
|
|
|
|
if ( in_coords[0] == dataCoord ) { result.x = xAxis->dataToWorld( pos.x ); is_3d = true; }
|
|
if ( in_coords[1] == dataCoord ) { result.y = yAxis->dataToWorld( pos.y ); is_3d = true; }
|
|
if ( in_coords[2] == dataCoord ) { result.z = zAxis->dataToWorld( pos.z ); is_3d = true; }
|
|
|
|
if ( in_coords[0] == worldCoord ) { result.x = pos.x; is_3d = true; }
|
|
if ( in_coords[1] == worldCoord ) { result.y = pos.y; is_3d = true; }
|
|
if ( in_coords[2] == worldCoord ) { result.z = pos.z; is_3d = true; }
|
|
|
|
if ( is_3d ) {
|
|
result = t.world3DToCanvas3( result );
|
|
} else {
|
|
if ( in_coords[0] == normCoord ) result.x = normalizedXToCanvas( pos.x );
|
|
if ( in_coords[1] == normCoord ) result.y = normalizedYToCanvas( pos.y );
|
|
if ( in_coords[2] == normCoord ) result.z = pos.z;
|
|
|
|
if ( in_coords[0] == mmCoord ) result.x = QSCoord::mmToPixels( pos.x, dpi );
|
|
if ( in_coords[1] == mmCoord ) result.y = QSCoord::mmToPixels( pos.y, dpi );
|
|
if ( in_coords[2] == mmCoord ) result.z = QSCoord::mmToPixels( pos.z, dpi );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt3f QSAxes3D::canvasToMixed( const QSPt3f& pos, CoordinateSystem out_coords[3], double dpi, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const
|
|
// if there is at least one dataCoord or worldCoord all remaining normCoords and mmCoord are treaten as worldCoord
|
|
{
|
|
QSPt3f result;
|
|
|
|
bool is_3d = false;
|
|
if ( out_coords[0] == worldCoord ) is_3d = true;
|
|
if ( out_coords[1] == worldCoord ) is_3d = true;
|
|
if ( out_coords[2] == worldCoord ) is_3d = true;
|
|
|
|
result = t.canvas3ToWorld3D( pos );
|
|
|
|
if ( out_coords[0] == dataCoord ) { result.x = xAxis->worldToData( result.x ); is_3d = true; }
|
|
if ( out_coords[1] == dataCoord ) { result.y = yAxis->worldToData( result.y ); is_3d = true; }
|
|
if ( out_coords[2] == dataCoord ) { result.z = zAxis->worldToData( result.z ); is_3d = true; }
|
|
|
|
if ( !is_3d ) {
|
|
if ( out_coords[0] == normCoord ) result.x = canvasToNormalizedX( pos.x );
|
|
if ( out_coords[1] == normCoord ) result.y = canvasToNormalizedY( pos.y );
|
|
if ( out_coords[2] == normCoord ) result.z = pos.z;
|
|
|
|
if ( out_coords[0] == mmCoord ) result.x = QSCoord::pixelsToMM( pos.x, dpi );
|
|
if ( out_coords[1] == mmCoord ) result.y = QSCoord::pixelsToMM( pos.y, dpi );
|
|
if ( out_coords[2] == mmCoord ) result.z = QSCoord::pixelsToMM( pos.z, dpi );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
|
|
{
|
|
QSAxes::loadStateFromStream( stream, factory );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes3D::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
|
|
{
|
|
QSAxes::saveStateToStream( stream, factory );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|