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.

822 lines
27 KiB

/***************************************************************************
qsplot.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"qsplot.h"
#include"qsaxis.h"
#include"qsaxes3d.h"
#include"qsprojection3d.h"
#include<assert.h>
#include<vector.h>
#include<algo.h>
QSPlot::QSPlot(QSAxes* parent, const char * name )
:QSAxesChild( parent, name )
{
assert( parent );
m_busy = false;
m_is_legend = true;
m_axes = parent;
m_drv = NULL;
// default axes
for( int axis_type=0; axis_type<5; axis_type++ ) m_daxes[axis_type] = m_axes->axisOfType((QSAxis::AxisType )axis_type);
m_title_str = tr("Untitled plot");
connect( m_axes, SIGNAL(sigChildRemoved(QSData*)), this, SLOT(axisRemoved(QSData*)) );
}
//-------------------------------------------------------------//
QSPlot::~QSPlot()
{
}
//-------------------------------------------------------------//
void QSPlot::axisRemoved( QSData *axis )
// find another axis to bind to
{
for( int axis_type=0; axis_type<5; axis_type++ )
if ( m_daxes[axis_type] == axis ) m_daxes[axis_type] = m_axes->axisOfType((QSAxis::AxisType )axis_type);
}
//-------------------------------------------------------------//
void QSPlot::setDefaultAxis( QSAxis *axis )
{
if ( axis && axis->parentAxes() == m_axes ) SET_PROPERTY( m_daxes[axis->type()], axis );
}
//-------------------------------------------------------------//
void QSPlot::setDefaultXAxis( int axisIndex )
{
setDefaultAxis( m_axes->axis(axisIndex) );
}
//-------------------------------------------------------------//
void QSPlot::setDefaultYAxis( int axisIndex )
{
setDefaultAxis( m_axes->axis(axisIndex) );
}
//-------------------------------------------------------------//
void QSPlot::setDefaultZAxis( int axisIndex )
{
setDefaultAxis( m_axes->axis(axisIndex) );
}
//-------------------------------------------------------------//
void QSPlot::setDefaultVAxis( int axisIndex )
{
setDefaultAxis( m_axes->axis(axisIndex) );
}
//-------------------------------------------------------------//
QSPt2f QSPlot::dataToWorld( const QSPt2f& p ) const
{
return QSPt2f( m_daxes[QSAxis::XAxisType]->dataToWorld(p.x),
m_daxes[QSAxis::YAxisType]->dataToWorld(p.y) );
}
//-------------------------------------------------------------//
QSPt3f QSPlot::dataToWorld( const QSPt3f& p ) const
{
return QSPt3f( m_daxes[QSAxis::XAxisType]->dataToWorld(p.x),
m_daxes[QSAxis::YAxisType]->dataToWorld(p.y),
m_daxes[QSAxis::ZAxisType]->dataToWorld(p.z) );
}
//-------------------------------------------------------------//
QSPt3f QSPlot::dataToWorldV( const QSPt3f& p ) const
{
return QSPt3f( m_daxes[QSAxis::XAxisType]->dataToWorld(p.x),
m_daxes[QSAxis::YAxisType]->dataToWorld(p.y),
m_daxes[QSAxis::VAxisType]->dataToWorld(p.z) );
}
//-------------------------------------------------------------//
QSPt2f QSPlot::worldToData( const QSPt2f& p ) const
{
return QSPt2f( m_daxes[QSAxis::XAxisType]->worldToData(p.x),
m_daxes[QSAxis::YAxisType]->worldToData(p.y) );
}
//-------------------------------------------------------------//
QSPt3f QSPlot::worldToData( const QSPt3f& p ) const
{
return QSPt3f( m_daxes[QSAxis::XAxisType]->worldToData(p.x),
m_daxes[QSAxis::YAxisType]->worldToData(p.y),
m_daxes[QSAxis::ZAxisType]->worldToData(p.z) );
}
//-------------------------------------------------------------//
QSPt3f QSPlot::worldToDataV( const QSPt3f& p ) const
{
return QSPt3f( m_daxes[QSAxis::XAxisType]->worldToData(p.x),
m_daxes[QSAxis::YAxisType]->worldToData(p.y),
m_daxes[QSAxis::VAxisType]->worldToData(p.z) );
}
//-------------------------------------------------------------//
void QSPlot::setLegendItemVisible( bool visible )
{
SET_PROPERTY( m_is_legend, visible );
}
//-------------------------------------------------------------//
bool QSPlot::start()
{
allocRuntimeData();
m_busy = true;
return false;
}
//-------------------------------------------------------------//
bool QSPlot::step()
{
return false;
}
//-------------------------------------------------------------//
void QSPlot::end()
{
freeRuntimeData();
m_busy = false;
}
//-------------------------------------------------------------//
void QSPlot::allocRuntimeData()
{
assert( m_axes );
m_cpos = m_axes->m_cpos;
m_csize = m_axes->m_csize;
m_bkg_handler = m_axes->m_bkg_handler;
m_curr_dpi = m_axes->run_dpi();
m_drv = m_axes->run_gDriver();
m_proj = m_axes->proj();
}
//-------------------------------------------------------------//
void QSPlot::freeRuntimeData()
{
m_drv = NULL;
}
//-------------------------------------------------------------//
bool QSPlot::getAxisRange( QSAxis*, double&, double& )
{
return false;
}
//-------------------------------------------------------------//
QString QSPlot::posInfo( QSPt2f& )
{
return QString::null;
}
//-------------------------------------------------------------//
QSPt2f QSPlot::legendItemSize( QSDrv * )
{
return QSPt2f(0,0);
}
//-------------------------------------------------------------//
void QSPlot::drawLegendItem( const QSPt2f&, QSDrv * )
{
}
//-------------------------------------------------------------//
void QSPlot::setGradient( const QSGGradient& newGradient )
{
if ( m_gradient != newGradient ) {
parametersChanging();
m_gradient = newGradient;
parametersChanged();
}
}
//-------------------------------------------------------------//
void QSPlot::setGradientProperty( const QString& string )
{
setGradient( toQSGGradient(string) );
}
//-------------------------------------------------------------//
void QSPlot::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
{
QSAxesChild::loadStateFromStream( stream, factory );
}
//-------------------------------------------------------------//
void QSPlot::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
{
QSAxesChild::saveStateToStream( stream, factory );
}
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
QSPlot2D::QSPlot2D( QSAxes *parentAxes, const char *name )
:QSPlot( parentAxes, name )
{
}
//-------------------------------------------------------------//
QSPlot2D::~QSPlot2D()
{
}
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
//-------------------------------------------------------------//
#define MAX_BUFF_SIZE 60
struct QSPlot3D::plot3d_runtime_data {
QSPlot3D *m_plot;
const QSProjection *m_proj;
double *first_level;
double *last_level;
double *after_last_level;
int nlevels;
double *level_values;
QSGFill *level_fills;
QSGLine *level_lines;
QSGFill polygon_fills[MAX_BUFF_SIZE];
QSPt3f polygon_normals[MAX_BUFF_SIZE];
QSPt3f canvas_buff[MAX_BUFF_SIZE];
QSPt3f clip_buff_1[MAX_BUFF_SIZE];
QSPt3f clip_buff_2[MAX_BUFF_SIZE];
QSPt3f clip_buff_3[MAX_BUFF_SIZE];
double clip_value_buff_1[MAX_BUFF_SIZE];
double clip_value_buff_2[MAX_BUFF_SIZE];
double clip_value_buff_3[MAX_BUFF_SIZE];
bool edge_buff_1[MAX_BUFF_SIZE];
bool edge_buff_2[MAX_BUFF_SIZE];
bool edge_buff_3[MAX_BUFF_SIZE];
bool all_edges[MAX_BUFF_SIZE]; // filled with true
QSDrv *m_drv;
QSDrv::CNormals m_cnormals;
QSDrv::CColors m_ccolors;
QSDrv::COrdering m_corder;
int find_level_greater_than( double value );
void draw_divided_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const bool *edges, int auto_color );
void draw_4d_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const double *values, const bool *edges, int auto_color );
inline void draw_simple_polygon( const QSPt3f pts[], int npoints,
const QSPt3f *norm, const QSGFill& f,
const bool *edges = NULL, int auto_color = 0 );
inline void draw_clipped_polygon( const QSPt3f pts[], int npoints,
const QSPt3f *norm, const QSGFill& f,
QSPt3f clip_pts[], int nclip_pts,
bool *edges = NULL, int auto_color = 0 );
void cut_polygon( double level, const QSPt3f *pts, int npts, const bool *in_edges,
QSPt3f *above_pts, int *above_npts, bool *above_edges,
QSPt3f *under_pts, int *under_npts, bool *under_edges );
void cut_polygon4d( double level,
const QSPt3f *input_pts, int input_npts, const double *input_values, const bool *in_edges,
QSPt3f *above_pts, int *above_npts, double *above_values, bool *above_edges,
QSPt3f *under_pts, int *under_npts, double *under_values, bool *under_edges );
};
//-------------------------------------------------------------//
QSPlot3D::QSPlot3D( QSAxes* parent, const char * name )
:QSPlot( parent, name )
{
d = NULL;
m_edge_auto_color = -50;
m_divide = false;
m_clipping = true;
m_topbottom = true;
m_colored = true;
#define FONTS_NUM 0
#define FILLS_NUM 2
#define LINES_NUM 1
#define POINTS_NUM 1
initAttributeTables( FONTS_NUM, FILLS_NUM, LINES_NUM, POINTS_NUM );
}
//-------------------------------------------------------------//
QSPlot3D::~QSPlot3D()
{
}
//-------------------------------------------------------------//
void QSPlot3D::setEdgeAutoColor( int value )
{
SET_PROPERTY( m_edge_auto_color, value );
}
//-------------------------------------------------------------//
void QSPlot3D::setClipping( bool clipping )
{
m_clipping = clipping;
}
//-------------------------------------------------------------//
void QSPlot3D::setTopBottom( bool enabled )
{
SET_PROPERTY( m_topbottom, enabled );
}
//-------------------------------------------------------------//
void QSPlot3D::setAutoDivide( bool enabled )
{
SET_PROPERTY( m_divide, enabled );
}
//-------------------------------------------------------------//
void QSPlot3D::setColored( bool enabled )
{
SET_PROPERTY( m_colored, enabled );
}
//-------------------------------------------------------------//
#define BOX_SPACE 2.0
#define BOX_WIDTH 20.0
#define BOX_HEIGHT 100.0
QSPt2f QSPlot3D::standardLegendItemSize( QSDrv *m_drv, QSAxis *axis, const QString& title )
{
double boxSpace = m_drv->toPixels(BOX_SPACE);
QSPt2f boxSize( m_drv->toPixels(BOX_WIDTH),
m_drv->toPixels(BOX_HEIGHT) );
QSPt2f tsize = m_drv->rTextSize( 270, title );
QSPt2f lsize;
int nr_labels = 0;
const list<QSAxisTic> *tics = axis->tics();
list<QSAxisTic>::const_iterator curr = tics->begin();
list<QSAxisTic>::const_iterator last = tics->end();
while( curr != last ) {
if ( !(*curr).m_major ) {
curr++;
continue;
}
if ( !(*curr).m_label.isEmpty() ) {
QSPt2f size = m_drv->rTextSize( (*curr).m_angle, (*curr).m_label );
lsize.x = QMAX(lsize.x, size.x);
lsize.y = QMAX(lsize.y, size.y);
}
curr++;
nr_labels++;
}
boxSize.y = QMAX(boxSize.y,nr_labels*lsize.y);
return QSPt2f( tsize.x+boxSpace+boxSize.x+boxSpace+boxSpace+boxSpace+lsize.x, QMAX(tsize.y,boxSize.y) );
}
//-------------------------------------------------------------//
void QSPlot3D::drawStandardLegendItem( const QSPt2f& pos, QSDrv *m_drv, QSAxis *axis, const QString& title, const QSGGradient *gradient )
{
double boxSpace = m_drv->toPixels(BOX_SPACE);
QSPt2f boxSize( m_drv->toPixels(BOX_WIDTH),
m_drv->toPixels(BOX_HEIGHT) );
// title
QSPt2f tsize = m_drv->rTextSize( 270, title );
double height = boxSize.y = standardLegendItemSize(m_drv,axis,title).y;
m_drv->drawRText( QSPt2f(pos.x,pos.y+height/2.0), 270, title, AlignHCenter | AlignTop );
// gradient
QSGFill f;
int h=256;
QSPt2f m_cpos( pos.x+tsize.x+boxSpace, pos.y+(height-boxSize.y)/2.0 );
m_drv->setLine( QSGLine::invisibleLine );
for ( int i=0; i<h; i++ ) {
gradient->fill( double(h-i)/h, f );
m_drv->setFill( f );
QSPt2f p1( m_cpos.x, m_cpos.y+i*boxSize.y/h);
QSPt2f p2( m_cpos.x+boxSize.x, m_cpos.y+(i+1)*boxSize.y/h);
m_drv->drawRect( p1, p2 );
}
QSGLine l; m_drv->setLine( l );
m_cpos.x = m_cpos.x+boxSize.x;
// labels
const list<QSAxisTic> *tics = axis->tics();
list<QSAxisTic>::const_iterator curr = tics->begin();
list<QSAxisTic>::const_iterator last = tics->end();
while( curr != last ) {
double ypos = m_cpos.y+(1.0-(*curr).m_pos)*boxSize.y;
if ( (*curr).m_major ) m_drv->drawLine( QSPt2f(m_cpos.x,ypos), QSPt2f(m_cpos.x-2.0*boxSpace,ypos) );
else m_drv->drawLine( QSPt2f(m_cpos.x,ypos), QSPt2f(m_cpos.x-0.5*boxSpace,ypos) );
m_drv->drawRText( QSPt2f(m_cpos.x+boxSpace+boxSpace+boxSpace,ypos), (*curr).m_angle, (*curr).m_label, AlignLeft | AlignVCenter );
curr++;
}
}
//-------------------------------------------------------------//
void QSPlot3D::allocRuntimeData()
{
QSPlot::allocRuntimeData();
d = new plot3d_runtime_data();
d->m_plot = this;
d->m_drv = m_drv;
d->m_proj = m_proj;
if ( m_drv ) {
m_cnormals = d->m_cnormals = m_drv->cNormals();
m_ccolors = d->m_ccolors = m_drv->cColors();
m_corder = d->m_corder = m_drv->cOrdering();
if ( m_cnormals == QSDrv::NoNormals ) m_cnormals = d->m_cnormals = QSDrv::MeshNormal; // was && light()
}
QSAxis *axis = m_daxes[QSAxis::VAxisType];
const list<QSAxisTic> *tics = m_daxes[QSAxis::VAxisType]->tics();
d->nlevels = tics->size();
d->level_values = new double[d->nlevels+2];
d->level_fills = new QSGFill[d->nlevels+2];
d->level_lines = new QSGLine[d->nlevels+2];
// the first level at 0.0 ( everything under will be transparent
d->level_lines[0] = QSGLine::invisibleLine;
d->level_fills[0] = QSGFill::Transparent;
d->level_values[0] = 0.0;
d->nlevels = d->nlevels+1;
// all tics from axis
list<QSAxisTic>::const_iterator curr_tic = tics->begin();
for( int i=1; i<d->nlevels; i++ ) {
d->level_lines[i] = curr_tic->m_line;
d->level_values[i] = curr_tic->m_pos;
d->level_fills[i] = curr_tic->m_fill;
// put gradient to axis
if ( !curr_tic->m_is_fill_defined ) {
if ( colored() ) m_gradient.fill( d->level_values[i], d->level_fills[i] );
else d->level_fills[i] = m_settings.fills[TMeshFill];
}
curr_tic++;
}
// the last level above the last tic
if ( d->level_values[d->nlevels-1] < 1.0 ) {
d->level_lines[d->nlevels] = QSGLine::invisibleLine;
d->level_values[d->nlevels] = 1.0;
// take this in a special way
if ( !axis->reversed() && axis->lastTic().m_is_fill_defined )
d->level_fills[d->nlevels] = axis->lastTic().m_fill;
else m_gradient.fill( 1.0, d->level_fills[d->nlevels] );
if ( !colored() ) d->level_fills[d->nlevels] = m_settings.fills[TMeshFill];
d->nlevels = d->nlevels+1;
}
d->first_level = &d->level_values[0];
d->last_level = &d->level_values[d->nlevels-1];
d->after_last_level = &d->level_values[d->nlevels];
for( int i=0; i<MAX_BUFF_SIZE; i++ ) d->all_edges[i] = true;
if ( d->m_drv ) {
d->m_drv->setTopBottom( topBottom() );
d->m_drv->setBottomFill( fill(BMeshFill) );
}
}
//-------------------------------------------------------------//
void QSPlot3D::freeRuntimeData()
{
delete[] d->level_lines;
delete[] d->level_fills;
delete[] d->level_values;
QSPlot::freeRuntimeData();
delete d; d=NULL;
}
//-------------------------------------------------------------//
//
// WYKOSIC FILL I OBLICZAC WLASNORECZNIE
//
//
void QSPlot3D::drawPolygon( const QSPt3f pts[], int npoints, QSPt3f *norm, const double *values, const bool *edges )
// if tvertex != -1 then norm[0] is not nessesary
{
if ( !m_divide ) {
if ( m_ccolors == QSDrv::VertexColors ) {
for( int i=0; i<npoints; i++ )
if ( colored() ) m_gradient.fill( pts[i].z, d->polygon_fills[i] );
else d->polygon_fills[i] = m_settings.fills[TMeshFill];
} else {
if ( colored() ) {
double sum_z = 0.0; for( int i=0; i<npoints; i++ ) sum_z += pts[i].z;
m_gradient.fill( sum_z/npoints, d->polygon_fills[0] );
} else {
d->polygon_fills[0] = m_settings.fills[TMeshFill];
}
}
m_drv->drawPoly3( pts, npoints, norm, d->polygon_fills, edges, m_edge_auto_color );
} else {
if ( !values ) d->draw_divided_polygon( pts, npoints, norm, edges, m_edge_auto_color );
else d->draw_4d_polygon( pts, npoints, norm, values, edges, m_edge_auto_color );
}
}
//-------------------------------------------------------------//
void QSPlot3D::plot3d_runtime_data::draw_divided_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const bool *edges, int auto_color )
// draws polygon cut by z levels
{
if ( npoints == 0 ) return;
double min_z = pts[0].z;
double max_z = pts[0].z;
for( int i=1; i<npoints; i++ ) {
double curr_z = pts[i].z;
min_z = QMIN( min_z, curr_z );
max_z = QMAX( max_z, curr_z );
}
// first level
int start_level = find_level_greater_than( min_z );
// try to avoid complicated processing if it is not absolutely needed
if ( start_level<nlevels && level_values[start_level]<max_z ) {
int ninput_pts = npoints;
int nabove_pts = 0;
int nunder_pts = 0;
QSPt3f *input_pts = const_cast<QSPt3f*>(pts);
QSPt3f *above_pts = clip_buff_1;
QSPt3f *under_pts = clip_buff_2;
bool *in_edges = edges ? const_cast<bool*>(edges) : all_edges;
bool *under_edges = edge_buff_1;
bool *above_edges = edge_buff_2;
// the level plane crosses through out polygon
int level_nr = start_level;
while( level_nr<nlevels && ninput_pts > 0 ) {
cut_polygon( level_values[level_nr],
input_pts, ninput_pts, in_edges,
above_pts, &nabove_pts, above_edges,
under_pts, &nunder_pts, under_edges );
// draw polygon under the current level
// TO CHECK: why it sometimes produces nunder_pts==0
if ( level_nr>0 && nunder_pts>0 ) draw_clipped_polygon( pts, npoints, norm, level_fills[level_nr], under_pts, nunder_pts, under_edges, auto_color );
// in first pass stop to use pts ( which is const )
if ( input_pts == pts ) { input_pts = clip_buff_3; in_edges = edge_buff_3; }
// rotate buffers: input_pts <-> above_pts
QSPt3f *temp_pts = input_pts; input_pts = above_pts; above_pts = temp_pts; ninput_pts = nabove_pts;
bool *temp_edges = in_edges; in_edges = above_edges; above_edges = temp_edges;
level_nr++;
}
} else {
// polygon contained in the level - no cuts or polygon above the highest level or below the lowest one ( out of drawing area )
if ( start_level<nlevels && start_level>0 ) draw_simple_polygon( pts, npoints, norm, level_fills[start_level], edges, auto_color );
}
}
//-------------------------------------------------------------//
void QSPlot3D::plot3d_runtime_data::draw_4d_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const double *values, const bool *edges, int auto_color )
// dravs polygons cut by the v levels ( 4d data )
{
if ( npoints == 0 ) return;
double min_v = values[0];
double max_v = values[0];
for( int i=1; i<npoints; i++ ) {
double curr_v = values[i];
min_v = QMIN( min_v, curr_v );
max_v = QMAX( max_v, curr_v );
}
int level_nr = find_level_greater_than( min_v );
if ( level_nr<nlevels && level_values[level_nr]<max_v ) {
int ninput_pts = npoints;
int nabove_pts = 0;
int nunder_pts = 0;
QSPt3f *input_pts = const_cast<QSPt3f*>(pts);
double *input_val = const_cast<double*>(values);
QSPt3f *above_pts = clip_buff_1;
double *above_val = clip_value_buff_1;
QSPt3f *under_pts = clip_buff_2;
double *under_val = clip_value_buff_2;
bool *in_edges = edges ? const_cast<bool*>(edges) : all_edges;
bool *under_edges = edge_buff_1;
bool *above_edges = edge_buff_2;
while( level_nr<nlevels && ninput_pts>0 ) {
cut_polygon4d( level_values[level_nr],
input_pts, ninput_pts, input_val, in_edges,
above_pts, &nabove_pts, above_val, above_edges,
under_pts, &nunder_pts, under_val, under_edges );
// draw polygon under the current level ( do not draw anything under level 0 )
if ( level_nr>0 ) draw_clipped_polygon( pts, npoints, norm, level_fills[level_nr], under_pts, nunder_pts, under_edges, auto_color );
// in first pass stop to use pts ( which is const )
if ( input_pts == pts ) { input_pts = clip_buff_3; input_val = clip_value_buff_3; in_edges = edge_buff_3; }
// rotate buffers: input_pts <-> above_pts
QSPt3f *temp_pts = input_pts; input_pts = above_pts; above_pts = temp_pts;
double *temp_val = input_val; input_val = above_val; above_val = temp_val;
bool *temp_edges = in_edges; in_edges = above_edges; above_edges = temp_edges;
ninput_pts = nabove_pts;
level_nr++;
}
} else {
// polygon is contained in some level or it is above all levels all it is under all levels ( not drawn in the last two cases )
if ( level_nr<nlevels && level_nr>0 ) draw_simple_polygon( pts, npoints, norm, level_fills[level_nr], edges, auto_color );
}
}
//-------------------------------------------------------------//
inline void QSPlot3D::plot3d_runtime_data::draw_simple_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const QSGFill& f, const bool *edges, int auto_color )
{
polygon_fills[0] = f;
if ( m_ccolors == QSDrv::VertexColors ) for( int i=1; i<npoints; i++ ) polygon_fills[i] = f;
m_drv->drawPoly3( pts, npoints, norm, polygon_fills, edges, auto_color );
}
//-------------------------------------------------------------//
inline void QSPlot3D::plot3d_runtime_data::draw_clipped_polygon( const QSPt3f pts[], int npoints, const QSPt3f *norm, const QSGFill& f, QSPt3f clip_pts[], int nclip_pts, bool *edges, int auto_color )
{
polygon_fills[0] = f;
if ( m_ccolors == QSDrv::VertexColors ) for( int i=1; i<nclip_pts; i++ ) polygon_fills[i] = f;
polygon_normals[0] = norm[0];
if ( m_cnormals == QSDrv::VertexNormals ) QSProjection::clipVertexNormals( pts, npoints, clip_pts, nclip_pts, &norm[1], &polygon_normals[1] );
m_drv->drawPoly3( clip_pts, nclip_pts, polygon_normals, polygon_fills, edges, auto_color );
}
//-------------------------------------------------------------//
int QSPlot3D::plot3d_runtime_data::find_level_greater_than( double value )
// find first level > value or return d->nlevels if all levels are lower then value
{
double *ptr = lower_bound( first_level, after_last_level, value );
int result = ptr < after_last_level ? ptr-first_level : nlevels;
return result;
}
//-------------------------------------------------------------//
void QSPlot3D::plot3d_runtime_data::cut_polygon( double level, const QSPt3f *pts, int npts, const bool *in_edges,
QSPt3f *above_pts, int *above_npts, bool *above_edges,
QSPt3f *under_pts, int *under_npts, bool *under_edges )
{
bool p_under;
bool s_under;
*above_npts = 0;
*under_npts = 0;
const QSPt3f *p;
const QSPt3f *s = &pts[npts-1]; s_under = ( s->z <= level );
for( int i=0; i<npts; i++ ) {
p = &pts[i]; p_under = ( p->z <= level );
if ( p_under && s_under ) { under_edges[(*under_npts)] = in_edges[i]; under_pts[(*under_npts)++] = *p; }
else
if ( !p_under && !s_under ) { above_edges[(*above_npts)] = in_edges[i]; above_pts[(*above_npts)++] = *p; }
else {
double t = (level-s->z)/(p->z-s->z);
QSPt3f c( s->x + t*(p->x-s->x),
s->y + t*(p->y-s->y),
level );
if ( p_under ) under_edges[(*under_npts)] = false; else under_edges[(*under_npts)] = in_edges[i];
if ( !p_under ) above_edges[(*above_npts)] = false; else above_edges[(*above_npts)] = in_edges[i];
under_pts[(*under_npts)++] = c;
above_pts[(*above_npts)++] = c;
if ( p_under ) { under_edges[(*under_npts)] = in_edges[i]; under_pts[(*under_npts)++] = *p; }
if ( !p_under ) { above_edges[(*above_npts)] = in_edges[i]; above_pts[(*above_npts)++] = *p; }
}
s = p; s_under = p_under;
}
}
//-------------------------------------------------------------//
void QSPlot3D::plot3d_runtime_data::cut_polygon4d( double level,
const QSPt3f *input_pts, int input_npts, const double *input_val, const bool *in_edges,
QSPt3f *above_pts, int *above_npts, double *above_val, bool *above_edges,
QSPt3f *under_pts, int *under_npts, double *under_val, bool *under_edges )
{
bool p_under;
bool s_under;
*above_npts = 0;
*under_npts = 0;
const QSPt3f *p;
const double *pv;
const QSPt3f *s = &input_pts[input_npts-1];
const double *sv = &input_val[input_npts-1];
s_under = ( *sv <= level );
for( int i=0; i<input_npts; i++ ) {
p = &input_pts[i];
pv = &input_val[i];
p_under = ( *pv <= level );
if ( p_under && s_under ) { under_edges[(*under_npts)] = in_edges[i]; under_pts[*under_npts] = *p; under_val[*under_npts] = *pv; (*under_npts)++; }
else
if ( !p_under && !s_under ) { above_edges[(*above_npts)] = in_edges[i]; above_pts[*above_npts] = *p; above_val[*above_npts] = *pv; (*above_npts)++; }
else {
double t = (level-*sv)/(*pv-*sv);
QSPt3f c( s->x + t*(p->x-s->x),
s->y + t*(p->y-s->y),
s->z + t*(p->z-s->z) );
if ( p_under ) under_edges[(*under_npts)] = false; else under_edges[(*under_npts)] = in_edges[i];
if ( !p_under ) above_edges[(*above_npts)] = false; else above_edges[(*above_npts)] = in_edges[i];
under_pts[*under_npts] = c; under_val[*under_npts] = level; (*under_npts)++;
above_pts[*above_npts] = c; above_val[*above_npts] = level; (*above_npts)++;
if ( p_under ) { under_edges[(*under_npts)] = in_edges[i]; under_pts[*under_npts] = *p; under_val[*under_npts] = *pv; (*under_npts)++; }
if ( !p_under ) { above_edges[(*above_npts)] = in_edges[i]; above_pts[*above_npts] = *p; above_val[*above_npts] = *pv; (*above_npts)++; }
}
s = p; sv = pv; s_under = p_under;
}
}
//-------------------------------------------------------------//
void QSPlot3D::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
{
QSPlot::loadStateFromStream( stream, factory );
}
//-------------------------------------------------------------//
void QSPlot3D::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
{
QSPlot::saveStateToStream( stream, factory );
}
//-------------------------------------------------------------//