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.

940 lines
34 KiB

/***************************************************************************
qsfigure.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 "qsfigure.h"
#include "qsdrv.h"
#include "qsconsole.h"
#include <algo.h>
#include <assert.h>
//
// Draw order ( painer algorithm )
// 1. For each facet remember its index and z-depth in depth_sorted_facets
// 2. Sort depth_sorted_facets
// 3. From depth_sorted_facets.beign() to depth_sorted_facets.end()
// get index to facet
// draw facet
//
//
// Calculating normal to vertices
// Normal to vertex is calculated as an average of normals to all
// facets which contain this vertex. Unfortunately the same vertex may
// be put a few times ito a vertex table - so you should compare all vertices to find out
// which of them are actually the same vertex.
// 1. For each VERTEX put its global index to sorted_global_vertex_table
// 2. Sort it using vcomp or icomp object
// - map all coordinates to <0,1> and round to the m_accuracy digits after the point
// - sort by x, next by y, next by z,
// 3. Now all the same vertices on the screen are also neighbours in sorted_global_vertex_table.
// When drawing:
// 4. But how you can find vertex for example nr. 5 in sorted_global_vertex_table.
// Index 5 in pos_in_sorted_global_vertex_table points to the position in sorted_global_vertex_table where the vertex nr 5
// resides.
// 5. Now potentially equal vertices are:
// sorted_global_vertex_table[pos_in_sorted_global_vertex_table[5]+1], sorted_global_vertex_table[pos_in_sorted_global_vertex_table[5]+2], ..
// sorted_global_vertex_table[pos_in_sorted_global_vertex_table[5]-1], sorted_global_vertex_table[pos_in_sorted_global_vertex_table[5]-2], ..
// Check them to find out if they are really equal ..
// 6. For each equal vertex find out to which facet it belongs, calculate normal to this facet.
// 7. Sum all normals and calculate an average
// We need something less complicated !
//-------------------------------------------------------------//
struct QSFigure::figure_runtime_data {
enum stage { OrderVertices = 0,
InitFind = 1,
FindNeighbours = 2,
InitDraw = 3,
DrawFigure = 4,
Finished = 5 };
int pi;
int pj;
QSAxis *xaxis;
QSAxis *yaxis;
QSAxis *zaxis;
QSAxis *vaxis;
int first_vertex; // order vertices in signle facet ( clockwise or anti-clockwise )
int vertex_step;
int stage;
int cmode; // see CMode
int vertex_count;
int facet_count;
bool is_4d_data; // is v coordinate available
bool is_index_table; // use indexes to build polygons
bool is_ordered; // is a special drawing order
QSPt3f *vertex_data_buff; // vertices of the current facet - temporary buffer ( length vertex_count )
// vertex number 'nr' of the given facet doesn't need to have position
// 'nr' in this buffer - order can be reversed ( normals ! ) see
// d->first_vertex and d->vertex_step
QSPt3f *vertex_world_buff; // as above - vertices in the world3D coordinates - temporary buffer ( vertex_count )
double *vertex_value_buff;
QSPt3f *vertex_temp_buff; // another temporary buffer for vertices of some facet. ( vertex_count )
QSPt3f *vertex_norm_buff; // normals to vertices buffer plus normat to the whole facet ( vertex_count+1)
QSMatrix *xm;
QSMatrix *ym;
QSMatrix *zm;
QSMatrix *vm;
QSMatrix *im;
QSGPoint point_mark;
// description of a single facet
struct facet_t {
int i; double z;
};
vector<facet_t>* depth_sorted_facets;
// Object for comparing depth of facets. Used with depth_sorted_facets - Ordering facets.
struct comp_t : public binary_function<facet_t, facet_t, bool> {
inline bool operator()( const facet_t& f1, const facet_t& f2 ) { return furthermost_first ? f1.z<f2.z : f1.z>f2.z; }
bool furthermost_first; // further first
} comp;
// Object for comparing vertices of facets.
// Find the same vertices for an average normal calculating.
// 1. compare x coordinate
// 2. compare y coordinate
// 3. compare z coordinate
struct vcomp_t : public binary_function<int, int, bool> {
// return global_vertex(v1) < global_vertex(v2)
// v1 and v2 are normalized numbers
bool operator()( int v1, int v2 ) {
int vertex1 = d->vertex( v1 );
int vertex2 = d->vertex( v2 );
int facet1 = d->facet( v1 );
int facet2 = d->facet( v2 );
double val1 = vroundx(d->xm->value(facet1,vertex1));
double val2 = vroundx(d->xm->value(facet2,vertex2));
if ( val1 > val2 ) return false;
else if ( val1 == val2 ) {
val1 = vroundy(d->ym->value(facet1,vertex1));
val2 = vroundy(d->ym->value(facet2,vertex2));
if ( val1 > val2 ) return false;
else if ( val1 == val2 ) {
val1 = vroundz(d->zm->value(facet1,vertex1));
val2 = vroundz(d->zm->value(facet2,vertex2));
if ( val1 >= val2 ) return false;
}
}
return true;
}
// map to <0,1> and round to ac digits after the point
inline double vroundx( double value ) { return floor((value-minx)*acsx+0.5); }
inline double vroundy( double value ) { return floor((value-miny)*acsy+0.5); }
inline double vroundz( double value ) { return floor((value-minz)*acsz+0.5); }
figure_runtime_data *d;
double acsx; // accuracy/scalex
double acsy; // accuracy/scaley
double acsz; // accuracy/scalez
double minx;
double miny;
double minz;
} vcomp;
// Compare vertices of facets for the case with the table of indices.
// Find the same vertices for an average normal calculating.
struct icomp_t : public binary_function<int, int, bool> {
// return global_vertex(v1) < global_vertex(v2)
inline bool operator()( int v1, int v2 ) {
return (int)d->im->value(d->facet(v1),d->vertex(v1)) < (int)d->im->value(d->facet(v2),d->vertex(v2));
}
figure_runtime_data *d;
} icomp;
vector<facet_t>::iterator bit;
vector<facet_t>::iterator eit;
vector<int>* sorted_global_vertex_table;
vector<int>::iterator bvit;
vector<int>::iterator evit;
vector<int>* pos_in_sorted_global_vertex_table;
// returns index which vertex 'vertex' of facet 'facet' has in 'pos_to_sorted_global_vertex_table'
inline int global_vertex_index( int facet, int vertex ) {
return facet*vertex_count+vertex;
}
inline int facet( int global_vertex_index ) {
return global_vertex_index/vertex_count;
}
inline int vertex( int global_vertex_index ) {
return global_vertex_index%vertex_count;
}
vector<int>* processed_facets; // neighbouring facets ( vertex_count ? )
inline bool facet_processed( int facet ) {
return binary_search(processed_facets->begin(),processed_facets->end(),facet);
}
inline void set_facet_processed( int facet ) {
processed_facets->insert(lower_bound(processed_facets->begin(),processed_facets->end(),facet),facet);
}
inline void clear_processed_facets() {
processed_facets->erase( processed_facets->begin(),processed_facets->end() );
}
};
/*
enum CMode { One,
MAuto,
VAuto,
MUserG,
MUserRGB,
MUserRGBA,
VUserG,
VUserRGB,
VUserRGBA };
*/
// QSGFill *vertex_fill_buff; // fills of vertices buffer ( vertex_count )
//-------------------------------------------------------------//
QSFigure::QSFigure(QSAxes* parent, const char * name)
:QSPlot3D(parent,name)
{
assert( parent );
m_accuracy = 4;
m_extremes_valid = false;
m_minmax_v_valid = false;
m_title_str = tr("Untitled figure");
m_dmin.set( 0.0, 0.0, 0.0 );
m_dmax.set( 0.0, 0.0, 0.0 );
m_vmin = 0.0;
m_vmax = 0.0;
#define CHANNELS_NUM 5
initChannelTable( CHANNELS_NUM );
}
//-------------------------------------------------------------//
QSFigure::~QSFigure()
{
}
//-------------------------------------------------------------//
void QSFigure::setVertexCompareAccuracy( int accuracy )
{
SET_PROPERTY( m_accuracy, accuracy );
}
//-------------------------------------------------------------//
void QSFigure::dataChanged( int channel )
// Ouu. We need to calculate new extremes in data
// Refresh data on screen also.
{
if ( channel == -1 ||
channel == VXCoord ||
channel == VYCoord ||
channel == VZCoord ||
channel == VTableI ) m_extremes_valid = false;
if ( channel == VVCoord ) m_minmax_v_valid = false;
QSPlot3D::dataChanged( channel );
}
//-------------------------------------------------------------//
void QSFigure::allocRuntimeData()
{
QSPlot3D::allocRuntimeData();
d = new figure_runtime_data();
d->depth_sorted_facets = NULL;
d->vertex_data_buff = NULL;
d->vertex_norm_buff = NULL;
d->vertex_world_buff = NULL;
d->vertex_value_buff = NULL;
d->vertex_temp_buff = NULL;
// d->vertex_fill_buff = NULL;
d->sorted_global_vertex_table = NULL;
d->pos_in_sorted_global_vertex_table = NULL;
d->processed_facets = NULL;
d->xaxis = defaultAxis(QSAxis::XAxisType);
d->yaxis = defaultAxis(QSAxis::YAxisType);
d->zaxis = defaultAxis(QSAxis::ZAxisType);
d->vaxis = defaultAxis(QSAxis::VAxisType);
d->stage = 0;
init_data();
bool vertex_order_reverse = false;
if (d->xaxis->reversed()) vertex_order_reverse = !vertex_order_reverse;
if (d->yaxis->reversed()) vertex_order_reverse = !vertex_order_reverse;
if (d->zaxis->reversed()) vertex_order_reverse = !vertex_order_reverse;
if ( vertex_order_reverse ) { d->first_vertex = d->vertex_count-1; d->vertex_step= - 1; }
else { d->first_vertex = 0; d->vertex_step = 1; }
d->point_mark = m_settings.points[PointMark];
}
//-------------------------------------------------------------//
void QSFigure::init_data()
// Check sizes of tables and which table with vertices we will be using.
{
d->facet_count = 0;
d->vertex_count = 0;
if ( matrixCols( VXCoord ) == matrixCols( VYCoord ) &&
matrixRows( VXCoord ) == matrixRows( VYCoord ) &&
matrixCols( VYCoord ) == matrixCols( VZCoord ) &&
matrixRows( VYCoord ) == matrixRows( VZCoord ) &&
matrixRows( VXCoord ) > 0 &&
matrixCols( VXCoord ) > 0 ) {
d->facet_count = matrixRows( VXCoord );
d->vertex_count = matrixCols( VXCoord );
}
d->is_4d_data = false;
if ( matrixCols( VVCoord ) == matrixCols( VXCoord ) &&
matrixRows( VVCoord ) == matrixRows( VXCoord ) ) {
d->is_4d_data = true;
}
d->is_index_table = false;
if ( matrixCols( VTableI ) > 0 && matrixRows( VTableI ) > 0 ) {
d->is_index_table = true;
d->vertex_count = matrixCols( VTableI );
d->facet_count = matrixRows( VTableI );
}
// clip buffers etc.
if ( d->vertex_count > 40 ) {
d->vertex_count = 0;
d->facet_count = 0;
}
// ordering of facets
d->is_ordered = ( m_corder != QSDrv::NoOrdering );
d->comp.furthermost_first = ( m_corder == QSDrv::FurtherFirst );
// facets data
d->xm = matrix( VXCoord );
d->ym = matrix( VYCoord );
d->zm = matrix( VZCoord );
d->vm = matrix( VVCoord );
d->im = matrix( VTableI );
}
//-------------------------------------------------------------//
void QSFigure::freeRuntimeData()
{
free_buffers();
delete d; d=NULL;
QSPlot3D::freeRuntimeData();
}
//-------------------------------------------------------------//
bool QSFigure::getAxisRange( QSAxis *axis, double& min, double& max )
{
allocRuntimeData();
if ( d->facet_count == 0 || d->vertex_count == 0 ) {
freeRuntimeData();
return false;
}
if ( !m_extremes_valid || !m_minmax_v_valid ) {
QSPt3f *vertex_buff = new QSPt3f[d->vertex_count+1];
double *value_buff = new double[d->vertex_count+1];
for( int pi=0; pi<d->facet_count; pi++ ) {
QSPt3f facet_min;
QSPt3f facet_max;
double value_min;
double value_max;
get_facet( pi, vertex_buff, value_buff );
facet_max.x = facet_min.x = vertex_buff[0].x;
facet_max.y = facet_min.y = vertex_buff[0].y;
facet_max.z = facet_min.z = vertex_buff[0].z;
value_min = value_max = value_buff[0];
for ( int k=1; k<d->vertex_count; k++ ) {
double x = vertex_buff[k].x ;
double y = vertex_buff[k].y ;
double z = vertex_buff[k].z ;
double v = value_buff[k];
if ( x < facet_min.x ) facet_min.x = x;
if ( y < facet_min.y ) facet_min.y = y;
if ( z < facet_min.z ) facet_min.z = z;
if ( x > facet_max.x ) facet_max.x = x;
if ( y > facet_max.y ) facet_max.y = y;
if ( z > facet_max.z ) facet_max.z = z;
if ( v < value_min ) value_min = v;
if ( v > value_max ) value_max = v;
}
if ( facet_min.x < m_dmin.x || pi == 0 ) m_dmin.x = facet_min.x;
if ( facet_min.y < m_dmin.y || pi == 0 ) m_dmin.y = facet_min.y;
if ( facet_min.z < m_dmin.z || pi == 0 ) m_dmin.z = facet_min.z;
if ( facet_max.x > m_dmax.x || pi == 0 ) m_dmax.x = facet_max.x;
if ( facet_max.y > m_dmax.y || pi == 0 ) m_dmax.y = facet_max.y;
if ( facet_max.z > m_dmax.z || pi == 0 ) m_dmax.z = facet_max.z;
if ( value_min < m_vmin || pi == 0 ) m_vmin = value_min;
if ( value_max > m_vmax || pi == 0 ) m_vmax = value_max;
}
delete[] vertex_buff;
delete[] value_buff;
m_extremes_valid = true;
m_minmax_v_valid = true;
}
if ( axis==d->xaxis ) { min = m_dmin.x; max = m_dmax.x; }
else if ( axis==d->yaxis ) { min = m_dmin.y; max = m_dmax.y; }
else if ( axis==d->zaxis ) { min = m_dmin.z; max = m_dmax.z; }
else if ( axis==d->vaxis && !d->is_4d_data ) { min = m_dmin.z; max = m_dmax.z; }
else if ( axis==d->vaxis && d->is_4d_data ) { min = m_vmin; max = m_vmax; }
else { freeRuntimeData(); return false; }
freeRuntimeData();
return true;
}
//-------------------------------------------------------------//
void QSFigure::get_facet( int facet, QSPt3f *vert, double *values )
// Return all vertex of an 'nr' facet in 'vert' table.
// This table must be large enough to contain all vertices.
{
int i = d->first_vertex;
if ( d->is_index_table ) {
for( int vertex=0; vertex<d->vertex_count; vertex++, i+=d->vertex_step ) {
int vertex_index = int( d->im->value( facet, vertex ) );
if ( vertex_index <0 || vertex_index >= d->xm->rows() ) {
QSConsole::write( tr("Figure:%1 : Invalid index %2 at row=%3, col=%4 ").arg(title()).arg(vertex_index).arg(facet).arg(vertex) );
vert[i].set(sqrt(-1.0),sqrt(-1.0),sqrt(-1.0));
if ( d->is_4d_data && values ) values[i] = sqrt(-1.0);
} else {
vert[i].set( d->xm->value( vertex_index, 0 ),
d->ym->value( vertex_index, 0 ),
d->zm->value( vertex_index, 0 ) );
if ( d->is_4d_data && values ) values[i] = d->vm->value( vertex_index, 0 );
}
}
} else {
for( int vertex=0; vertex<d->vertex_count; vertex++, i+=d->vertex_step ) {
vert[i].set( d->xm->value( facet, vertex ),
d->ym->value( facet, vertex ),
d->zm->value( facet, vertex ) );
if ( d->is_4d_data && values ) values[i] = d->vm->value( facet, vertex );
}
}
}
//-------------------------------------------------------------//
bool QSFigure::start()
{
QSPlot3D::start();
if ( d->facet_count == 0 || d->vertex_count == 0 ) return false;
alloc_buffers();
// init_colors();
d->stage = 0;
d->pi = 0;
d->pj = 0;
return true;
}
//-------------------------------------------------------------//
void QSFigure::alloc_buffers()
{
assert( d );
free_buffers();
d->vertex_data_buff = new QSPt3f[d->vertex_count];
d->vertex_value_buff = new double[d->vertex_count];
d->vertex_world_buff = new QSPt3f[d->vertex_count];
d->vertex_temp_buff = new QSPt3f[d->vertex_count];
d->vertex_norm_buff = new QSPt3f[d->vertex_count+1];
// d->vertex_fill_buff = new QSGFill[d->vertex_count];
if ( d->is_ordered ) d->depth_sorted_facets = new vector<figure_runtime_data::facet_t>( d->facet_count );
if ( m_cnormals == QSDrv::VertexNormals ) {
d->sorted_global_vertex_table = new vector<int>( d->vertex_count*d->facet_count );
d->pos_in_sorted_global_vertex_table = new vector<int>( d->vertex_count*d->facet_count );
d->processed_facets = new vector<int>();
d->processed_facets->reserve( d->vertex_count );
}
}
//-------------------------------------------------------------//
void QSFigure::free_buffers()
{
assert( d );
delete d->depth_sorted_facets; d->depth_sorted_facets = NULL;
delete d->sorted_global_vertex_table; d->sorted_global_vertex_table = NULL;
delete d->pos_in_sorted_global_vertex_table; d->pos_in_sorted_global_vertex_table = NULL;
delete d->processed_facets; d->processed_facets = NULL;
delete[] d->vertex_data_buff; d->vertex_data_buff = NULL;
delete[] d->vertex_value_buff; d->vertex_value_buff = NULL;
delete[] d->vertex_world_buff; d->vertex_world_buff = NULL;
delete[] d->vertex_temp_buff; d->vertex_temp_buff = NULL;
delete[] d->vertex_norm_buff; d->vertex_norm_buff = NULL;
// delete[] d->vertex_fill_buff; d->vertex_fill_buff = NULL;
}
//-------------------------------------------------------------//
/*
void QSFigure::init_colors()
// Uff !!
{
assert( d );
if ( !colored() ) { d->cmode = figure_runtime_data::One; return; }
if ( m_ccolors == QSDrv::VertexColors ) d->cmode = figure_runtime_data::VAuto;
else d->cmode = figure_runtime_data::MAuto;
}
*/
//-------------------------------------------------------------//
/*
void QSFigure::get_facet_colors( int findex, QSGFill *vertex_fill_buff )
// vertex_world_buff must be defined
//
{
int k;
double sum = 0.0;
switch( d->cmode ) {
case figure_runtime_data::VAuto:
for( k=0; k<d->vertex_count; k++ ) m_gradient.fill( d->vertex_world_buff[k].z, vertex_fill_buff[k] );
break;
case figure_runtime_data::MAuto:
for( k=0; k<d->vertex_count; k++ ) sum+=d->vertex_world_buff[k].z;
m_gradient.fill( sum/d->vertex_count, vertex_fill_buff[0] );
break;
default: vertex_fill_buff[0] = fill(TMeshFill);
if ( m_ccolors == QSDrv::VertexColors ) for( k=0; k<d->vertex_count; k++ ) vertex_fill_buff[k] = vertex_fill_buff[0];
break;
}
}
*/
//-------------------------------------------------------------//
//-------------------------------------------------------------//
bool QSFigure::step()
{
switch( d->stage ) {
case figure_runtime_data::OrderVertices: order_vertices_step(); break;
case figure_runtime_data::InitFind: init_find_neighbours(); break;
case figure_runtime_data::FindNeighbours: find_neighbours_step(); break;
case figure_runtime_data::InitDraw: init_draw_figure(); break;
case figure_runtime_data::DrawFigure: draw_figure_step(); break;
default: return false;
}
return true;
}
//-------------------------------------------------------------//
void QSFigure::end()
{
free_buffers();
QSPlot3D::end();
}
//-------------------------------------------------------------//
void QSFigure::order_vertices_step()
{
if ( !d->is_ordered ) { d->pi = 0; d->stage ++; return; }
double z;
double maxz;
double minz;
int curr_step = 0;
while ( d->pi<d->facet_count ) {
get_facet( d->pi, d->vertex_data_buff );
minz = maxz = m_axes->proj()->world3DToCanvas3(dataToWorld(d->vertex_data_buff[0])).z;
for ( int k=1; k<d->vertex_count; k++ ) {
z = m_axes->proj()->world3DToCanvas3(dataToWorld(d->vertex_data_buff[k])).z;
if ( z > maxz ) maxz = z;
if ( z < minz ) minz = z;
}
(*d->depth_sorted_facets)[d->pi].i = d->pi;
(*d->depth_sorted_facets)[d->pi].z = d->comp.furthermost_first ? minz : maxz;
d->pi++; if ( ++curr_step > work_steps && m_bkg_handler ) return;
}
d->bit = d->depth_sorted_facets->begin();
d->eit = d->depth_sorted_facets->end();
make_heap( d->bit, d->eit, d->comp );
d->pi = 0; d->stage ++;
}
//-------------------------------------------------------------//
void QSFigure::init_find_neighbours()
{
if ( m_cnormals == QSDrv::VertexNormals ) {
d->icomp.d = d;
d->vcomp.d = d;
double accuracy = pow( 10, m_accuracy );
d->vcomp.minx = m_dmin.x;
d->vcomp.miny = m_dmin.y;
d->vcomp.minz = m_dmin.z;
if ( m_dmax.x > m_dmin.x ) d->vcomp.acsx = accuracy/(m_dmax.x-m_dmin.x);
else d->vcomp.acsx = accuracy;
if ( m_dmax.y > m_dmin.y ) d->vcomp.acsy = accuracy/(m_dmax.y-m_dmin.y);
else d->vcomp.acsy = accuracy;
if ( m_dmax.z > m_dmin.z ) d->vcomp.acsz = accuracy/(m_dmax.z-m_dmin.z);
else d->vcomp.acsz = accuracy;
for( int global_vertex=0; global_vertex<d->vertex_count*d->facet_count; global_vertex++ )
(*d->sorted_global_vertex_table)[global_vertex] = global_vertex;
d->bvit = d->sorted_global_vertex_table->begin();
d->evit = d->sorted_global_vertex_table->end();
// sorting make_heap + pop_heap
if ( d->is_index_table ) make_heap( d->bvit, d->evit, d->icomp );
else make_heap( d->bvit, d->evit, d->vcomp );
}
d->stage ++;
}
//-------------------------------------------------------------//
void QSFigure::find_neighbours_step()
{
if ( m_cnormals != QSDrv::VertexNormals ) { d->pi=0 ; d->stage ++; return; }
int curr_step = 0;
while ( d->evit != d->bvit ) {
if ( d->is_index_table ) pop_heap( d->bvit, d->evit, d->icomp );
else pop_heap( d->bvit, d->evit, d->vcomp );
d->evit --; if ( ++curr_step > work_steps && m_bkg_handler ) return;
}
for( int k=0; k<d->facet_count*d->vertex_count; k++ )
(*d->pos_in_sorted_global_vertex_table)[(*d->sorted_global_vertex_table)[k]]=k;
d->pi = 0; d->stage ++;
}
//-------------------------------------------------------------//
void QSFigure::init_draw_figure()
{
m_drv->setLine( line(MeshLine) );
d->pi = 0; d->stage ++;
}
//-------------------------------------------------------------//
void QSFigure::draw_figure_step()
// facet_count - number of facets
// vertex_count - number of vertices in a facet
// vertex_world_buff[] - buffer of coordinates of vertices
// vertex_fill_buff[] - buffer of fills of vertices
// vertex_norm_buff[0] - normal to the current facet
// vertex_norm_buff[] - buffer of normals to vertices
//
{
int facet;
int curr_step = 0;
while( d->pi< d->facet_count ) {
// Get the current facet.
if ( d->is_ordered ) { pop_heap( d->bit, d->eit, d->comp ); d->eit--; }
facet = d->is_ordered?(*d->eit).i:d->pi;
get_facet( facet, d->vertex_data_buff, d->vertex_value_buff );
// Prepare all vertices.
map_facet_to_world( d->vertex_data_buff, d->vertex_world_buff );
// Update vertex_fill_buff with colors.
// get_facet_colors( facet, d->vertex_fill_buff );
// The normal to the current facet.
if ( m_cnormals != QSDrv::NoNormals ) d->vertex_norm_buff[0] = QSProjection::normal( d->vertex_world_buff, d->vertex_count );
// Normals to the vertices of the current facet
if ( m_cnormals == QSDrv::VertexNormals && d->vertex_count > 2 ) get_facet_normals( facet, &d->vertex_norm_buff[1] );
// Draw the final polygon.
double *value_buff = NULL;
if ( d->is_4d_data ) {
for( int i=0; i<d->vertex_count; i++ ) d->vertex_value_buff[i] = d->vaxis->dataToWorld( d->vertex_value_buff[i] );
value_buff = d->vertex_value_buff;
}
if ( d->vertex_count > 2 ) drawPolygon( d->vertex_world_buff, d->vertex_count, d->vertex_norm_buff, value_buff );
else
// lines
if ( d->vertex_count == 2 ) m_drv->drawLine3( d->vertex_world_buff[0], d->vertex_world_buff[1], NULL ); // no vertex_norm_buff
// trajectory/scatter plot
if ( d->vertex_count == 1 && facet > 0 && m_settings.lines[MeshLine].style != QSGLine::Invisible ) {
// connect succesive points with a line
// further end can overdraw closer end !
QSPt3f temp_wbuff[2];
// QSGFill temp_fbuff[2];
get_facet( facet-1, temp_wbuff );
map_facet_to_world( temp_wbuff, temp_wbuff );
// get_facet_colors( facet-1, temp_fbuff );
temp_wbuff[1] = d->vertex_world_buff[0];
// temp_fbuff[1] = d->vertex_fill_buff[0];
m_drv->drawLine3( temp_wbuff[0], temp_wbuff[1], NULL );
draw_point_marks( 2, temp_wbuff );
}
else
// draw points
draw_point_marks( d->vertex_count, d->vertex_world_buff );
d->pi++;
if ( ++curr_step > work_steps && m_bkg_handler ) return;
}
d->stage ++;
}
//-------------------------------------------------------------//
void QSFigure::draw_point_marks( int number, const QSPt3f* vertex_world_buff )
// points shoud be sorted by position ( further first or closer first )
{
if ( d->point_mark.style != QSGPoint::Invisible )
for ( int k=0; k<number; k++ ) {
/*
if ( d->cmode == figure_runtime_data::MUserG ||
d->cmode == figure_runtime_data::MUserRGB ||
d->cmode == figure_runtime_data::MUserRGBA ) d->point_mark.color = vertex_fill_buff[0].color;
if ( d->cmode == figure_runtime_data::VUserG ||
d->cmode == figure_runtime_data::VUserRGB ||
d->cmode == figure_runtime_data::VUserRGBA ) d->point_mark.color = vertex_fill_buff[k+1].color;
*/
if ( m_axes->proj()->clipPoint3(vertex_world_buff[k]) ) {
m_drv->drawPoint3( vertex_world_buff[k], d->point_mark );
}
}
m_drv->setLine( m_settings.lines[MeshLine] );
m_drv->setFill( m_settings.fills[TMeshFill] );
}
//-------------------------------------------------------------//
void QSFigure::map_facet_to_world( const QSPt3f *vertex_data_buff, QSPt3f *vertex_world_buff )
{
for( int k=0; k<d->vertex_count; k++ ) vertex_world_buff[k] = dataToWorld( vertex_data_buff[k] );
}
//#include<iostream.h>
void QSFigure::get_facet_normals( int facet, QSPt3f *normals )
// For each vertex accumulate normals of facet itself and all neighouring facets ( and next normalize the result ).
// Neighbouring facets are ones which share current vertex with this facet, How to find shared vertices
// ( it is difficult if the same vertex is put a few times into a vertex table ):
// 1. for each vertex of the facet - find this vertex in sorted_global_vertex_table[]
// 2. Test if neighbouring ( at previous and next positions ) vertices in this table have the same coordinates as our vertex:
// 3. If they have find a facet which they belong to, calculate normal to this facet and add this normal to the result
// . ( Take next vertex of a facet and go to 2 )
// 4. Normalize the result
{
int i=d->first_vertex;
for( int vertex=0; vertex<d->vertex_count; vertex++, i+=d->vertex_step ) {
/////////////////////////////////////////////
// Calculate normal for vertex 'vertex' //
/////////////////////////////////////////////
normals[i].set( 0.0, 0.0, 0.0 );
int bindex1 = (*d->pos_in_sorted_global_vertex_table)[d->global_vertex_index(facet,vertex)];
// test next position and add normal of current facet
get_vertex_normal( bindex1, bindex1, 1, &normals[i] );
// test previous positions
get_vertex_normal( bindex1, bindex1-1, -1, &normals[i] );
d->clear_processed_facets();
normals[i] = QSProjection::normalize( normals[i] );
}
}
//-------------------------------------------------------------//
void QSFigure::get_vertex_normal( int vertex_index, int search_start_index, int search_index_step, QSPt3f *normal )
// Calculate normal for vertex sorted_global_vertex_table[bindex1], by adding
// normals to all facets which the current vertex belongs to.
// Check only in one direction
{
int curr_index = search_start_index;
while( is_equal(vertex_index,curr_index) ) {
//Find a facet which vertex 'vert_index2' belongs to. All indices are indices to sorted_vertex_table .
int findex = d->facet( (*d->sorted_global_vertex_table)[curr_index] );
//////////////////////////////////////////////
// add normal of facet findex to the result//
//////////////////////////////////////////////
if ( !d->facet_processed(findex) ) {
d->set_facet_processed(findex);
get_facet( findex, d->vertex_temp_buff );
map_facet_to_world( d->vertex_temp_buff, d->vertex_temp_buff );
*normal = *normal + QSProjection::normal( d->vertex_temp_buff, d->vertex_count );
}
curr_index += search_index_step;
}
}
//-------------------------------------------------------------//
bool QSFigure::is_equal( int index1, int index2 )
// Compare two wertices sorted_global_vertex_table[index1] == sorted_global_vertex_table[index2].
{
int gnum = d->vertex_count*d->facet_count-1;
if ( index1 < 0 || index1 > gnum ||
index2 < 0 || index2 > gnum ) return false;
int v1 = (*d->sorted_global_vertex_table)[index1];
int v2 = (*d->sorted_global_vertex_table)[index2];
int vertex1 = d->vertex( v1 );
int vertex2 = d->vertex( v2 );
int facet1 = d->facet( v1 );
int facet2 = d->facet( v2 );
if ( d->is_index_table ) return int(d->im->value(facet1,vertex1)) == int(d->im->value(facet2,vertex2));
return d->vcomp.vroundx(d->xm->value(facet1,vertex1)) == d->vcomp.vroundx(d->xm->value(facet2,vertex2)) &&
d->vcomp.vroundy(d->ym->value(facet1,vertex1)) == d->vcomp.vroundy(d->ym->value(facet2,vertex2)) &&
d->vcomp.vroundz(d->zm->value(facet1,vertex1)) == d->vcomp.vroundz(d->zm->value(facet2,vertex2)) ;
}
//-------------------------------------------------------------//
QString QSFigure::posInfo( QSPt2f& pos )
{
if ( m_busy ) return QString::null;
allocRuntimeData();
QSPt2f p;
double pz = 0.0;
bool init = false;
double pdistance = 10.0*10.0;
QString result = QString::null;
QSPt3f *vertex_buff = new QSPt3f[d->vertex_count+1];
double *value_buff = new double[d->vertex_count+1];
for ( int f=0; f<d->facet_count; f++ ) {
get_facet( f, vertex_buff, value_buff );
for ( int k=0; k<d->vertex_count; k++ ) {
QSPt3f dpos = vertex_buff[k];;
double value = value_buff[k];
QSPt3f wpos = dataToWorld(dpos);
QSPt3f cpos = m_proj->world3DToCanvas3(wpos);
double distance = (pos.x-cpos.x)*(pos.x-cpos.x)+(pos.y-cpos.y)*(pos.y-cpos.y);
if ( distance < 5.0*5.0 && distance < pdistance && (cpos.z<pz||!init) ) {
pdistance = distance;
init = true; pz = cpos.z; p = QSPt2f(cpos.x,cpos.y);
result = QString(tr("row = "))+QString::number(f)+ "\n";
result += QString(tr("col = "))+QString::number(k)+ "\n";
result += QString(tr("X = "))+QString::number(dpos.x)+ "\n";
result += QString(tr("Y = "))+QString::number(dpos.y)+ "\n";
result += QString(tr("Z = "))+QString::number(dpos.z)+ "\n";
if ( d->is_4d_data )
result += QString(tr("V = "))+QString::number(value)+ "\n";
}
}
}
delete[] vertex_buff;
delete[] value_buff;
freeRuntimeData();
if ( result != QString::null ) pos = p;
return result;
}
//-------------------------------------------------------------//
QSPt2f QSFigure::legendItemSize( QSDrv *drv )
{
return standardLegendItemSize( drv, defaultAxis(QSAxis::ZAxisType), title() );
}
//-------------------------------------------------------------//
void QSFigure::drawLegendItem( const QSPt2f& pos, QSDrv *drv )
{
drawStandardLegendItem( pos, drv, defaultAxis(QSAxis::ZAxisType), title(), &m_gradient );
}
//-------------------------------------------------------------//
void QSFigure::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
{
QSPlot3D::loadStateFromStream( stream, factory );
}
//-------------------------------------------------------------//
void QSFigure::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
{
QSPlot3D::saveStateToStream( stream, factory );
}
//-------------------------------------------------------------//
QString QSFigure::channelVariable( int channel ) const
{
switch( channel ) {
case VXCoord: return "x";
case VYCoord: return "y";
case VZCoord: return "z";
case VVCoord: return "v";
case VTableI: return "i";
}
return QString::null;
}
//-------------------------------------------------------------//
QSFigure::ColumnType QSFigure::columnType( int channel, int column ) const
{
}