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.
664 lines
22 KiB
664 lines
22 KiB
13 years ago
|
/***************************************************************************
|
||
|
qsimage.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 "qsimage.h"
|
||
|
#include <math.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
struct QSImage::image_runtime_data {
|
||
|
enum Type { RGBImage, GrayImage, IndexedImage } type;
|
||
|
struct {
|
||
|
QSPt2 p1;
|
||
|
QSPt2 p2;
|
||
|
} rarea; // area to refresh
|
||
|
int pi;
|
||
|
int pj;
|
||
|
int lines;
|
||
|
int curr_x_index;
|
||
|
int curr_y_index;
|
||
|
QSAxis *xaxis;
|
||
|
QSAxis *yaxis;
|
||
|
QSAxis *vaxis;
|
||
|
QSMatrix *rm;
|
||
|
QSMatrix *gm;
|
||
|
QSMatrix *bm;
|
||
|
QSMatrix *pm;
|
||
|
int w, h, ph;
|
||
|
int *xbuff;
|
||
|
int *ybuff;
|
||
|
bool is_x_vector;
|
||
|
bool is_y_vector;
|
||
|
QSGFill fill;
|
||
|
QSDrv::PixmapBuffer buff;
|
||
|
};
|
||
|
|
||
|
#define CHANNELS_NUM 6
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
QSImage::QSImage(QSAxes* parent, const char * name)
|
||
|
:QSPlot2D(parent,name)
|
||
|
{
|
||
|
assert( parent );
|
||
|
m_use_gradient = true;
|
||
|
m_axes = parent;
|
||
|
m_evalid = false;
|
||
|
m_rawmode = false;
|
||
|
m_title_str = tr("Untitled image");
|
||
|
m_dmin = 0.0;
|
||
|
m_dmax = 0.0;
|
||
|
initChannelTable( CHANNELS_NUM );
|
||
|
initAttributeTables( 0, 0, 0, 0 );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
QSImage::~QSImage()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::setUseGradient( bool enable )
|
||
|
{
|
||
|
if ( m_use_gradient != enable ) {
|
||
|
parametersChanging();
|
||
|
m_use_gradient = enable;
|
||
|
parametersChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::setRawMode( bool enabled )
|
||
|
{
|
||
|
if ( m_rawmode != enabled ) {
|
||
|
parametersChanging();
|
||
|
m_rawmode = enabled;
|
||
|
m_evalid = false;
|
||
|
parametersChanged();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::allocRuntimeData()
|
||
|
{
|
||
|
QSPlot2D::allocRuntimeData();
|
||
|
d = new image_runtime_data();
|
||
|
d->is_x_vector = false;
|
||
|
d->is_y_vector = false;
|
||
|
d->xbuff = NULL;
|
||
|
d->ybuff = NULL;
|
||
|
d->pi = 0;
|
||
|
d->pj = 0;
|
||
|
d->xaxis = defaultAxis(QSAxis::XAxisType);
|
||
|
d->yaxis = defaultAxis(QSAxis::YAxisType);
|
||
|
d->vaxis = defaultAxis(QSAxis::VAxisType);
|
||
|
d->w = matrixCols( DataRed );
|
||
|
d->h = matrixRows( DataRed );
|
||
|
d->ph = matrixRows( Palette );
|
||
|
d->rm = matrix( DataRed );
|
||
|
d->gm = matrix( DataGreen );
|
||
|
d->bm = matrix( DataBlue );
|
||
|
d->pm = matrix( Palette );
|
||
|
|
||
|
// detect image type
|
||
|
d->type = image_runtime_data::GrayImage;
|
||
|
|
||
|
if ( matrixCols( Palette ) == 3 &&
|
||
|
matrixRows( Palette ) > 0 ) d->type = image_runtime_data::IndexedImage;
|
||
|
if ( matrixCols( DataGreen ) == d->w &&
|
||
|
matrixRows( DataGreen ) == d->h &&
|
||
|
matrixCols( DataBlue ) == d->w &&
|
||
|
matrixRows( DataBlue ) == d->h ) d->type = image_runtime_data::RGBImage;
|
||
|
|
||
|
if ( matrixCols( XVector ) == d->w+1 &&
|
||
|
matrixRows( XVector ) > 0 ) d->is_x_vector = true;
|
||
|
else d->is_x_vector = false;
|
||
|
|
||
|
if ( matrixRows( YVector ) == d->h+1 &&
|
||
|
matrixCols( YVector ) > 0 ) d->is_y_vector = true;
|
||
|
else d->is_y_vector = false;
|
||
|
|
||
|
|
||
|
if ( m_rawmode ) { m_dmin = 0.0; m_dmax = 255.0; m_evalid = true; }
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::freeRuntimeData()
|
||
|
{
|
||
|
delete[] d->xbuff; d->xbuff = NULL;
|
||
|
delete[] d->ybuff; d->ybuff = NULL;
|
||
|
delete d; d = NULL;
|
||
|
QSPlot2D::freeRuntimeData();
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::getAxisRange( QSAxis *axis, double& min, double& max )
|
||
|
{
|
||
|
allocRuntimeData();
|
||
|
if ( d->w == 0 || d->h == 0 ) { freeRuntimeData(); return false; }
|
||
|
|
||
|
if ( !m_evalid ) {
|
||
|
for( int j=0; j<d->h; j++ ) {
|
||
|
for( int i=0; i<d->w; i++ ) {
|
||
|
double vmax;
|
||
|
double vmin;
|
||
|
vmax = vmin = value(j,i,DataRed);
|
||
|
if ( d->type == image_runtime_data::RGBImage ) {
|
||
|
double vg = value( j, i, DataGreen );
|
||
|
double vb = value( j, i, DataBlue );
|
||
|
vmax = QMAX( vmax, QMAX( vg, vb ) );
|
||
|
vmin = QMIN( vmin, QMIN( vg, vb ) );
|
||
|
}
|
||
|
if ( i == 0 && j == 0 ) {
|
||
|
m_dmax = vmax;
|
||
|
m_dmin = vmin;
|
||
|
} else {
|
||
|
m_dmin = QMIN( m_dmin, vmin );
|
||
|
m_dmax = QMAX( m_dmax, vmax );
|
||
|
}
|
||
|
} // for ( i= ..
|
||
|
} // for ( j= ...
|
||
|
m_evalid = true;
|
||
|
}
|
||
|
|
||
|
double xmin = d->is_x_vector ? matrix(XVector)->value(0,0) : 0.0;
|
||
|
double xmax = d->is_x_vector ? matrix(XVector)->value(0,d->w) : d->w;
|
||
|
double ymin = d->is_y_vector ? matrix(YVector)->value(0,0) : 0.0;
|
||
|
double ymax = d->is_y_vector ? matrix(YVector)->value(d->h,0) : d->h;
|
||
|
if ( xmin > xmax ) { double xtemp = xmin; xmin = xmax; xmax = xtemp; }
|
||
|
if ( ymin > ymax ) { double ytemp = ymin; ymin = ymax; ymax = ytemp; }
|
||
|
|
||
|
if ( axis == d->xaxis ) { min = xmin; max = xmax; }
|
||
|
else if ( axis == d->yaxis ) { min = ymin; max = ymax; }
|
||
|
else if ( axis == d->vaxis && m_rawmode ) { min = 0.0; max = 255.0; }
|
||
|
else if ( axis == d->vaxis && !m_rawmode ) { min = m_dmin; max = m_dmax; }
|
||
|
else { freeRuntimeData(); return false; }
|
||
|
|
||
|
freeRuntimeData();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::start()
|
||
|
{
|
||
|
QSPlot2D::start();
|
||
|
|
||
|
if ( !init_buffers() ) return false;
|
||
|
|
||
|
// Init loops
|
||
|
d->pi = d->rarea.p1.x;
|
||
|
d->pj = d->rarea.p1.y;
|
||
|
d->curr_x_index = -999999; // see set_rgb
|
||
|
d->curr_y_index = -999999;
|
||
|
d->lines = 0;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::init_buffers()
|
||
|
{
|
||
|
// detect
|
||
|
QSPt2f p1;
|
||
|
QSPt2f p2;
|
||
|
p1.x = d->is_x_vector ? matrix(XVector)->value(0,0) : 0.0;
|
||
|
p1.y = d->is_y_vector ? matrix(YVector)->value(0,0) : 0.0;
|
||
|
p2.x = d->is_x_vector ? matrix(XVector)->value(0,d->w) : d->w;
|
||
|
p2.y = d->is_y_vector ? matrix(YVector)->value(d->h,0) : d->h;
|
||
|
|
||
|
p1 = m_axes->dataToCanvas(p1,d->xaxis,d->yaxis);
|
||
|
p2 = m_axes->dataToCanvas(p2,d->xaxis,d->yaxis);
|
||
|
|
||
|
QSPt2 cp1( int(p1.x+0.5), int(p1.y+0.5) );
|
||
|
QSPt2 cp2( int(p2.x+0.5), int(p2.y+0.5) );
|
||
|
|
||
|
if ( cp1.x > cp2.x ) { int temp = cp1.x; cp1.x = cp2.x; cp2.x = temp; }
|
||
|
if ( cp1.y > cp2.y ) { int temp = cp1.y; cp1.y = cp2.y; cp2.y = temp; }
|
||
|
|
||
|
|
||
|
// Intersect refresh area with clipping area
|
||
|
// clipping area is set in plot2d as an interior
|
||
|
// of the axis box.
|
||
|
if ( !clip_rect(cp1,cp2) ) return false;
|
||
|
|
||
|
// where bitmap starts
|
||
|
d->rarea.p1 = cp1;
|
||
|
d->rarea.p2 = cp2;
|
||
|
|
||
|
// X index buffer
|
||
|
// index buffer tells, for each screen pixel between rarea.x1 and
|
||
|
// rarea.x2, which data column is to be drawn at this position
|
||
|
d->xbuff = new int[d->rarea.p2.x-d->rarea.p1.x+1];
|
||
|
for ( int i=0; i<d->w; i++ ) { // for each data column
|
||
|
double dx1 = d->is_x_vector ? matrix(XVector)->value(0,i) : i;
|
||
|
double dx2 = d->is_x_vector ? matrix(XVector)->value(0,i+1) : i+1;
|
||
|
int cx1 = int(m_axes->dataToCanvas( QSPt2f(dx1,0.0), d->xaxis, d->yaxis ).x+0.5); //start pos of this column on the screen
|
||
|
int cx2 = int(m_axes->dataToCanvas( QSPt2f(dx2,0.0), d->xaxis, d->yaxis ).x+0.5); // end pos of this column on the screen
|
||
|
if ( cx2 < cx1 ) { int temp = cx1; cx1 = cx2; cx2 = temp; }
|
||
|
for ( int j=cx1; j<=cx2; j++ ) // for ach screen pixel beetween cx2 an cx1
|
||
|
if ( j>=d->rarea.p1.x && j<=d->rarea.p2.x ) d->xbuff[j-d->rarea.p1.x] = i;
|
||
|
}
|
||
|
|
||
|
// Y index buffer
|
||
|
d->ybuff = new int[d->rarea.p2.y-d->rarea.p1.y+1];
|
||
|
for ( int i=0; i<d->h; i++ ) {
|
||
|
double dy1 = d->is_y_vector ? matrix(YVector)->value(i,0) : i;
|
||
|
double dy2 = d->is_y_vector ? matrix(YVector)->value(i+1,0) : i+1;
|
||
|
int cy1 = int(m_axes->dataToCanvas( QSPt2f(0.0,dy1), d->xaxis, d->yaxis ).y+0.5);
|
||
|
int cy2 = int(m_axes->dataToCanvas( QSPt2f(0.0,dy2), d->xaxis, d->yaxis ).y+0.5);
|
||
|
if ( cy2 < cy1 ) { int temp = cy1; cy1 = cy2; cy2 = temp; }
|
||
|
for ( int j=cy1; j<=cy2; j++ )
|
||
|
if ( j>=d->rarea.p1.y && j<=d->rarea.p2.y ) d->ybuff[j-d->rarea.p1.y] = i;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::clip_rect( QSPt2& p1, QSPt2& p2 )
|
||
|
{
|
||
|
int cx1;
|
||
|
int cy1;
|
||
|
int cx2;
|
||
|
int cy2;
|
||
|
//dynamic_cast<const QSProjection2D*>(m_axes->proj())->getClipRect( &cx1, &cy1, &cx2, &cy2 );
|
||
|
QSPt2f pos1 = m_axes->proj()->world2DToCanvas( QSPt2f(0.0,0.0) );
|
||
|
QSPt2f pos2 = m_axes->proj()->world2DToCanvas( QSPt2f(1.0,1.0) );
|
||
|
cx1 = QMIN( int(pos1.x+0.5), int(pos2.x+0.5) );
|
||
|
cy1 = QMIN( int(pos1.y+0.5), int(pos2.y+0.5) );
|
||
|
cx2 = QMAX( int(pos1.x+0.5), int(pos2.x+0.5) );
|
||
|
cy2 = QMAX( int(pos1.y+0.5), int(pos2.y+0.5) );
|
||
|
int x01;
|
||
|
int y01;
|
||
|
int x02;
|
||
|
int y02;
|
||
|
if ( cx1 > p1.x ) x01 = cx1; else x01 = p1.x;
|
||
|
if ( cy1 > p1.y ) y01 = cy1; else y01 = p1.y;
|
||
|
if ( cx2 < p2.x ) x02 = cx2; else x02 = p2.x;
|
||
|
if ( cy2 < p2.y ) y02 = cy2; else y02 = p2.y;
|
||
|
|
||
|
x02 -= 1;
|
||
|
y02 -= 1;
|
||
|
|
||
|
if ( x02-x01 > 0 && y02-y01 > 0 ) {
|
||
|
p1.x = x01; p1.y = y01;
|
||
|
p2.x = x02; p2.y = y02;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::end()
|
||
|
{
|
||
|
// all clean-up work is done in freeRuntimeData()
|
||
|
QSPlot2D::end();
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::dataChanged( int channel )
|
||
|
// Ouu. We need to calculate new extremes in data
|
||
|
// Refresh data on screen also.
|
||
|
{
|
||
|
m_evalid = false;
|
||
|
m_dmin = m_dmax = 0.0;
|
||
|
QSPlot2D::dataChanged( channel );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::step()
|
||
|
{
|
||
|
int curr_step = 0;
|
||
|
while( d->pj <= d->rarea.p2.y ) {
|
||
|
|
||
|
// Get pixmap buffer for the next buff.lines lines
|
||
|
if ( d->lines == 0 ) {
|
||
|
d->buff.ptr = NULL;
|
||
|
m_drv->getPixmapBuffer( &d->buff, d->rarea.p2.x-d->rarea.p1.x+1, d->rarea.p2.y-d->pj+1 );
|
||
|
if ( d->buff.ptr == NULL || d->buff.lines == 0 ) { return false; }
|
||
|
m_ptr = d->buff.ptr;
|
||
|
d->lines = d->buff.lines;
|
||
|
}
|
||
|
int ypos = d->ybuff[d->pj-d->rarea.p1.y];
|
||
|
|
||
|
// Write scanlines to the buffer
|
||
|
while( d->pi <= d->rarea.p2.x ) {
|
||
|
set_rgb( m_ptr, d->xbuff[d->pi-d->rarea.p1.x], ypos );
|
||
|
d->pi ++; m_ptr += d->buff.po;
|
||
|
if ( curr_step++ > (work_steps<<5) && m_bkg_handler ) return true;
|
||
|
}
|
||
|
d->pj ++;
|
||
|
|
||
|
// Draw pixmap
|
||
|
if ( --d->lines == 0 ) {
|
||
|
QSPt2 ppos( d->rarea.p1.x, d->pj-d->buff.lines );
|
||
|
m_drv->drawPixmap( QSPt2f( ppos.x, ppos.y ), &d->buff );
|
||
|
}
|
||
|
|
||
|
// Set pointer to the next scanline
|
||
|
m_ptr = d->buff.ptr + (d->buff.lines-d->lines) * d->buff.lo;
|
||
|
d->pi = d->rarea.p1.x;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::set_rgb( unsigned char* p, int x_index, int y_index )
|
||
|
{
|
||
|
double dr = 0.0;
|
||
|
double dg = 0.0;
|
||
|
double db = 0.0;
|
||
|
|
||
|
if ( d->curr_x_index != x_index ||
|
||
|
d->curr_y_index != y_index ) {
|
||
|
|
||
|
dr = d->rm->value(y_index,x_index);//c
|
||
|
if ( d->type == image_runtime_data::RGBImage ) {
|
||
|
dg = d->gm->value(y_index,x_index);//c
|
||
|
db = d->bm->value(y_index,x_index);//c
|
||
|
}
|
||
|
// convert from data to world
|
||
|
if ( !m_rawmode ) {
|
||
|
if ( !m_use_gradient ) {
|
||
|
dr = d->vaxis->dataToWorld(dr)*255.0+0.5;
|
||
|
if ( d->type == image_runtime_data::RGBImage ) {
|
||
|
dg = d->vaxis->dataToWorld(dg)*255.0+0.5;
|
||
|
db = d->vaxis->dataToWorld(db)*255.0+0.5;
|
||
|
}
|
||
|
} else {
|
||
|
m_gradient.fill( d->vaxis->dataToWorld(dr), d->fill );
|
||
|
m_r = d->fill.color.r;
|
||
|
m_g = d->fill.color.g;
|
||
|
m_b = d->fill.color.b;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// take a palette value
|
||
|
if ( !m_use_gradient )
|
||
|
if ( d->type == image_runtime_data::IndexedImage ) {
|
||
|
if ( dr < 0 ) dr = 0;
|
||
|
if ( dr > d->ph-1 ) dr = d->ph-1;
|
||
|
|
||
|
int pindex = int(dr);
|
||
|
|
||
|
dr = d->pm->value( pindex,0 ); //c
|
||
|
dg = d->pm->value( pindex,1 );
|
||
|
db = d->pm->value( pindex,2 );
|
||
|
}
|
||
|
|
||
|
if ( !m_use_gradient ) {
|
||
|
if ( dr < 0.0 ) dr = 0.0;
|
||
|
if ( dr > 255.0 ) dr = 255.0;
|
||
|
}
|
||
|
|
||
|
// finally set m_r, m_g, m_b values
|
||
|
if ( !m_use_gradient )
|
||
|
if ( d->type == image_runtime_data::GrayImage ) {
|
||
|
m_r = m_g = m_b = (unsigned char )dr;
|
||
|
} else {
|
||
|
if ( dg < 0.0 ) dg = 0.0;
|
||
|
if ( db < 0.0 ) db = 0.0;
|
||
|
if ( dg > 255.0 ) dg = 255.0;
|
||
|
if ( db > 255.0 ) db = 255.0;
|
||
|
|
||
|
m_r = (unsigned char )dr;
|
||
|
m_g = (unsigned char )dg;
|
||
|
m_b = (unsigned char )db;
|
||
|
}
|
||
|
|
||
|
d->curr_x_index = x_index;
|
||
|
d->curr_y_index = y_index;
|
||
|
}
|
||
|
|
||
|
*p = 255; p += d->buff.co;// alpha
|
||
|
*p = m_r; p += d->buff.co;
|
||
|
*p = m_g; p += d->buff.co;
|
||
|
*p = m_b;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
QString QSImage::posInfo( QSPt2f& p )
|
||
|
{
|
||
|
if ( m_busy ) return QString::null;
|
||
|
|
||
|
int pindex;
|
||
|
QString result;
|
||
|
allocRuntimeData();
|
||
|
if ( !init_buffers() ) { freeRuntimeData(); return QString::null; }
|
||
|
|
||
|
QSPt2 pos( int(p.x+0.5), int(p.y+0.5) );
|
||
|
if ( pos.x >= d->rarea.p1.x && pos.x <= d->rarea.p2.x &&
|
||
|
pos.y >= d->rarea.p1.y && pos.y <= d->rarea.p2.y ) {
|
||
|
|
||
|
QSPt2 index( d->xbuff[pos.x-d->rarea.p1.x], d->ybuff[pos.y-d->rarea.p1.y] );
|
||
|
result = QString(tr(" row = ")) + QString::number(index.y) + "\n";
|
||
|
result += QString(tr(" col = ")) + QString::number(index.x) + "\n";
|
||
|
|
||
|
//QSPt2f p = m_proj->canvasToWorld2D( pos );
|
||
|
//p = worldToData( p );
|
||
|
//result += QString(tr(" X = ")) + QString::number(p.x) + "\n";
|
||
|
//result += QString(tr(" Y = ")) + QString::number(p.y) + "\n";
|
||
|
|
||
|
switch( d->type ) {
|
||
|
case image_runtime_data::GrayImage:
|
||
|
result += QString(tr(" value = ")) + QString::number(d->rm->value(index.y,index.x)) + "\n";
|
||
|
break;
|
||
|
case image_runtime_data::RGBImage:
|
||
|
result += QString(tr(" R = ")) + QString::number(d->rm->value(index.y,index.x)) + "\n";
|
||
|
result += QString(tr(" G = ")) + QString::number(d->gm->value(index.y,index.x)) + "\n";
|
||
|
result += QString(tr(" B = ")) + QString::number(d->bm->value(index.y,index.x)) + "\n";
|
||
|
break;
|
||
|
case image_runtime_data::IndexedImage:
|
||
|
pindex = (int )d->rm->value(index.y,index.x); pindex = QMAX( pindex, 0 ); pindex = QMIN( pindex, d->ph-1 );
|
||
|
result += QString(tr(" palette index = ")) + QString::number(pindex) + "\n";
|
||
|
result += QString(tr(" R = ")) + QString::number(d->pm->value(pindex,0)) + "\n";
|
||
|
result += QString(tr(" G = ")) + QString::number(d->pm->value(pindex,1)) + "\n";
|
||
|
result += QString(tr(" B = ")) + QString::number(d->pm->value(pindex,2)) + "\n";
|
||
|
/*
|
||
|
result += QString(tr(" G = ")) + QString::number(d->pm->ncol()) + "\n";
|
||
|
result += QString(tr(" B = ")) + QString::number(d->pm->ncol()) + "\n";
|
||
|
*/
|
||
|
default: break;
|
||
|
}
|
||
|
}
|
||
|
freeRuntimeData();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
bool QSImage::isClicked( const QSPt2f& pos )
|
||
|
{
|
||
|
if ( m_busy ) return false;
|
||
|
allocRuntimeData();
|
||
|
if ( !init_buffers() ) { freeRuntimeData(); return false; }
|
||
|
if ( pos.x >= d->rarea.p1.x && pos.x <= d->rarea.p2.x &&
|
||
|
pos.y >= d->rarea.p1.y && pos.y <= d->rarea.p2.y ) return true;
|
||
|
freeRuntimeData();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
#define BOX_SPACE 2.0
|
||
|
#define BOX_WIDTH 20.0
|
||
|
#define BOX_HEIGHT 100.0
|
||
|
|
||
|
QSPt2f QSImage::legendItemSize( QSDrv *drv )
|
||
|
{
|
||
|
double boxSpace = drv->toPixels(BOX_SPACE);
|
||
|
QSPt2f boxSize( drv->toPixels(BOX_WIDTH),
|
||
|
drv->toPixels(BOX_HEIGHT) );
|
||
|
QSPt2f tsize = drv->rTextSize( 270, title() );
|
||
|
QSPt2f lsize;
|
||
|
int nr_labels = 0;
|
||
|
QSAxis *axis = defaultAxis(QSAxis::VAxisType);
|
||
|
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 = 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 QSImage::drawLegendItem( const QSPt2f& pos, QSDrv *drv )
|
||
|
{
|
||
|
double boxSpace = drv->toPixels(BOX_SPACE);
|
||
|
QSPt2f boxSize( drv->toPixels(BOX_WIDTH),
|
||
|
drv->toPixels(BOX_HEIGHT) );
|
||
|
|
||
|
// detect image type and number of colors in gradient
|
||
|
int h = 256;
|
||
|
int type = image_runtime_data::GrayImage;
|
||
|
if ( matrixCols( Palette ) == 3 &&
|
||
|
matrixRows( Palette ) > 0 ) { type = image_runtime_data::IndexedImage; h = matrixRows( Palette ); }
|
||
|
if ( matrixCols( DataGreen ) == matrixCols( DataRed ) &&
|
||
|
matrixRows( DataGreen ) == matrixRows( DataRed ) &&
|
||
|
matrixCols( DataBlue ) == matrixCols( DataRed ) &&
|
||
|
matrixRows( DataBlue ) == matrixRows( DataRed ) ) type = image_runtime_data::RGBImage;
|
||
|
|
||
|
// title
|
||
|
QSPt2f tsize = drv->rTextSize( 270, title() );
|
||
|
double height = boxSize.y = legendItemSize(drv).y;
|
||
|
drv->drawRText( QSPt2f(pos.x,pos.y+height/2), 270, title(), AlignHCenter | AlignTop );
|
||
|
|
||
|
// gradient
|
||
|
QSAxis *axis = defaultAxis(QSAxis::VAxisType);
|
||
|
QSPt2f cpos( pos.x+tsize.x+boxSpace, pos.y+(height-boxSize.y)/2.0 );
|
||
|
drv->setLine( QSGLine::invisibleLine );
|
||
|
for ( int i=0; i<h; i++ ) {
|
||
|
int index = h-i-1;
|
||
|
QSGFill f;
|
||
|
QSPt2f p1( cpos.x, cpos.y+i*boxSize.y/h);
|
||
|
QSPt2f p2( cpos.x+boxSize.x, cpos.y+(i+1)*boxSize.y/h);
|
||
|
double x01 = cpos.x+boxSize.x/3.0;
|
||
|
double x02 = cpos.x+boxSize.x*2.0/3.0;
|
||
|
switch ( type ) {
|
||
|
case image_runtime_data::GrayImage:
|
||
|
if ( m_use_gradient ) m_gradient.fill( double(h-i)/h, f );
|
||
|
else f.color = QSGColor( index, index, index);
|
||
|
drv->setFill( f );
|
||
|
drv->drawRect( p1, p2 );
|
||
|
break;
|
||
|
case image_runtime_data::IndexedImage:
|
||
|
/*
|
||
|
f.color = QSGColor( (unsigned char )matrix(Palette)->value(index,0),
|
||
|
(unsigned char )matrix(Palette)->ncol(),
|
||
|
(unsigned char )matrix(Palette)->ncol() );
|
||
|
*/
|
||
|
f.color = QSGColor( (unsigned char )matrix(Palette)->value(index,0),
|
||
|
(unsigned char )matrix(Palette)->value(index,1),
|
||
|
(unsigned char )matrix(Palette)->value(index,2) );
|
||
|
|
||
|
drv->setFill( f );
|
||
|
drv->drawRect( p1, p2 );
|
||
|
break;
|
||
|
case image_runtime_data::RGBImage:
|
||
|
f.color = QSGColor( index, 0, 0 ); drv->setFill( f );
|
||
|
drv->drawRect( QSPt2f(p1.x,p1.y), QSPt2f(x01,p2.y) );
|
||
|
f.color = QSGColor( 0, index, 0 ); drv->setFill( f );
|
||
|
drv->drawRect( QSPt2f(x01,p1.y), QSPt2f(x02,p2.y) );
|
||
|
f.color = QSGColor( 0, 0, index ); drv->setFill( f );
|
||
|
drv->drawRect( QSPt2f(x02,p1.y), QSPt2f(p2.x,p2.y) );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
// frame
|
||
|
drv->setFill( QSGFill::transparentFill );
|
||
|
drv->drawRect( cpos, cpos+boxSize );
|
||
|
*/
|
||
|
QSGLine l; drv->setLine( l );
|
||
|
cpos.x = 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 ) {
|
||
|
if ( !(*curr).m_major ) { curr++; continue; }
|
||
|
double ypos = cpos.y+ (1.0-(*curr).m_pos)*boxSize.y+0.5;
|
||
|
drv->drawLine( QSPt2f(cpos.x,ypos), QSPt2f(cpos.x+boxSpace,ypos) );
|
||
|
drv->drawRText( QSPt2f(cpos.x+boxSpace+boxSpace+boxSpace,ypos), (*curr).m_angle, (*curr).m_label, AlignLeft | AlignVCenter );
|
||
|
curr++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
|
||
|
{
|
||
|
QSPlot2D::loadStateFromStream( stream, factory );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
void QSImage::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
|
||
|
{
|
||
|
QSPlot2D::saveStateToStream( stream, factory );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
QString QSImage::channelVariable( int channel ) const
|
||
|
{
|
||
|
switch( channel ) {
|
||
|
case DataRed: return "r";
|
||
|
case DataGreen: return "g";
|
||
|
case DataBlue: return "b";
|
||
|
case Palette: return "p";
|
||
|
case XVector: return "x";
|
||
|
case YVector: return "y";
|
||
|
}
|
||
|
return QString::null;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------//
|
||
|
|
||
|
QSImage::ColumnType QSImage::columnType( int channel, int column ) const
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|