Hi I am using qwtspectrogram to plot my array data but the problem i am having is scaling.. the qwt scales are distributed over the intervals x and y and the axis are dependent on the pixels. for example if I have a data set vector of (500x500) and i want to plot for 500mm x500mm its perfect because it is translated over the pixels but if i want to plot 500x500 number of points for 300mmx300mm it is a mess and it shows in the plot 500x500 i know i have to manage the x and y axis but I have no idea how to do that. I manage to play a little and display 500x500 for 250mmx250mm area but can not do for others.
my code is as shown below
class mydata: public QwtRasterData
{
char filepath[35];
QFile myfile;
QVector<qint16> fileBuf;
int pixel =500; // it represents the number of pixels in one row or column
int dial =1000;
public:
mydata()
{
setInterval( Qt::XAxis, QwtInterval( 0, (pixel)-1 ) );
setInterval( Qt::YAxis, QwtInterval( 0, (pixel)-1 ) );
setInterval( Qt::ZAxis, QwtInterval( -dial, dial ) );
{
sprintf_s(filepath, "c:\\myfile.bin");
myfile.setFileName(filepath);
if(!myfile.open(QIODevice::ReadOnly)) return;
QDataStream data(&myfile);
data.setByteOrder(QDataStream::LittleEndian);
while(!data.atEnd()) {
qint16 x;
data >> x;
fileBuf.append(x);
}
myfile.close();
}
}
virtual double value( double x, double y ) const//shifted
{
int x_pos = static_cast<int>(x);
int y_pos = static_cast<int>(y);
double c = (fileBuf[ ((x_pos)+((pixel-(y_pos))*pixel))]);
return c;
}
}
in short i have same number of pixels for different areas but i have same representation of axis in plot.
here is a class that converts double value of scale into string and display instead
class MyScaleDraw: public QwtScaleDraw
{
public:
MyScaleDraw()
{
setTickLength( QwtScaleDiv::MajorTick, 10 );
setTickLength( QwtScaleDiv::MinorTick, 2 );
setTickLength( QwtScaleDiv::MediumTick, 0 );
setLabelRotation( 0 );
setLabelAlignment( Qt::AlignLeft | Qt::AlignVCenter );
setSpacing( 10 );
}
virtual QwtText label( double value ) const
{
QwtText h=QwtText(QString::number(value*0.75); //use any scaling factor you want
return h;
}
};
include the following below code after creating a plot
d_plot->setAxisScaleDraw( QwtPlot::xBottom, new MyScaleDraw() );
d_plot->setAxisScaleDraw( QwtPlot::yLeft, new MyScaleDraw() );
this solved my problem
Related
I want to plot two colormaps. I want to plot them into the same window but into different axisrects. On top of each other. What happens is that the first color map is plotted nicely, but the second one is overlapping most of the axes and ticks and looks just awful.
Here is a minimal working example:
QCustomPlot * pCstmPlt = new QCustomPlot;
pCstmPlt->show();
QCPAxisRect *axisRect = pCstmPlt->axisRect(0);
axisRect->setupFullAxesBox(true);
QCPColorMap *colorMap = new QCPColorMap(axisRect->axis(QCPAxis::atBottom),axisRect->axis(QCPAxis::atLeft));
int Clrny = 100;
int Clrnx = 100;
colorMap->data()->setSize(Clrnx, Clrny);
colorMap->data()->setRange( QCPRange( 1,100 ), QCPRange( 1,100 ) );
double x, y, dVal;
for (int xIndex=0; xIndex<100; ++xIndex)
{
for (int yIndex=0; yIndex<100; ++yIndex)
{
colorMap->data()->cellToCoord(xIndex, yIndex, &x, &y);
dVal = ( xIndex * yIndex );
colorMap->data()->setCell(xIndex, yIndex, dVal);
}
}
// add a color scale:
QCPColorScale *pmycolorScale = new QCPColorScale(pCstmPlt);
pCstmPlt->plotLayout()->addElement(0, 1, pmycolorScale);
pmycolorScale->setType(QCPAxis::atRight);
colorMap->setColorScale(pmycolorScale);
colorMap->setGradient( QCPColorGradient::gpPolar );
axisRect = new QCPAxisRect(pCstmPlt,true);
axisRect->setupFullAxesBox(true);
pCstmPlt->plotLayout()->addElement(1,0,axisRect);
QCPColorMap *colorMap2 = new QCPColorMap(axisRect->axis(QCPAxis::atBottom),axisRect->axis(QCPAxis::atLeft));
colorMap2->data()->setSize(Clrnx, Clrny);
colorMap2->data()->setRange( QCPRange( 1,100 ), QCPRange( 1,100 ) );
for (int xIndex=0; xIndex<100; ++xIndex)
{
for (int yIndex=0; yIndex<100; ++yIndex)
{
colorMap2->data()->cellToCoord(xIndex, yIndex, &x, &y);
dVal = ( xIndex * yIndex );
colorMap2->data()->setCell(xIndex, yIndex, dVal);
}
}
// add a color scale:
QCPColorScale *pmycolorScale2 = new QCPColorScale(pCstmPlt);
pCstmPlt->plotLayout()->addElement(1, 1, pmycolorScale2);
pmycolorScale2->setType(QCPAxis::atRight);
colorMap2->setColorScale(pmycolorScale2);
colorMap2->setGradient( QCPColorGradient::gpPolar );
colorMap->rescaleDataRange();
colorMap2->rescaleDataRange();
pCstmPlt->rescaleAxes();
pCstmPlt->setMinimumSize(QSize(500,500));
The result looks like this:
So, clearly, the lower plot misses ticks and axes.
In case any one else will be wondering about this: The question was answered somewhere else,
https://www.qcustomplot.com/index.php/support/forum/2269
The trick was to put all axes on the "axes" layer with
axis->setLayer("axes");
I used QWT for my project. I used Qwtplotmagnifier for zoom.
I want to zoom in relative to the mouse cursor. Can you Help me?
I had the same problem and I could not find any answer, so here is mine.
Based on this post : Calculating view offset for zooming in at the position of the mouse cursor
In order to implement a GoogleMap-style zoom, you have to inherit from QwtPlotMagnifier and reimplement widgetWheelEvent in order to store the cursor position when a scroll happens, and rescale function, to change the behavior of the zoom.
//widgetWheelEvent method
void CenterMouseMagnifier::widgetWheelEvent(QWheelEvent *wheelEvent)
{
this->cursorPos = wheelEvent->pos();
QwtPlotMagnifier::widgetWheelEvent(wheelEvent);
}
For the rescale method, I used the source code and modified it. You need to use the QwtScaleMap object of the canvas to transform the mouse cursor coordinates into axis coordinates of your plot. And finally, you just need to apply the formula given in the other post.
//rescale method
void CenterMouseMagnifier::rescale(double factor)
{
QwtPlot* plt = plot();
if ( plt == nullptr )
return;
factor = qAbs( factor );
if ( factor == 1.0 || factor == 0.0 )
return;
bool doReplot = false;
const bool autoReplot = plt->autoReplot();
plt->setAutoReplot( false );
for ( int axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
{
if ( isAxisEnabled( axisId ) )
{
const QwtScaleMap scaleMap = plt->canvasMap( axisId );
double v1 = scaleMap.s1(); //v1 is the bottom value of the axis scale
double v2 = scaleMap.s2(); //v2 is the top value of the axis scale
if ( scaleMap.transformation() )
{
// the coordinate system of the paint device is always linear
v1 = scaleMap.transform( v1 ); // scaleMap.p1()
v2 = scaleMap.transform( v2 ); // scaleMap.p2()
}
double c=0; //represent the position of the cursor in the axis coordinates
if (axisId == QwtPlot::xBottom) //we only work with these two axis
c = scaleMap.invTransform(cursorPos.x());
if (axisId == QwtPlot::yLeft)
c = scaleMap.invTransform(cursorPos.y());
const double center = 0.5 * ( v1 + v2 );
const double width_2 = 0.5 * ( v2 - v1 ) * factor;
const double newCenter = c - factor * (c - center);
v1 = newCenter - width_2;
v2 = newCenter + width_2;
if ( scaleMap.transformation() )
{
v1 = scaleMap.invTransform( v1 );
v2 = scaleMap.invTransform( v2 );
}
plt->setAxisScale( axisId, v1, v2 );
doReplot = true;
}
}
plt->setAutoReplot( autoReplot );
if ( doReplot )
plt->replot();
}
This works fine for me.
Based on this forum post:
bool ParentWidget::eventFilter(QObject *o, QEvent *e)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if (mouseEvent->type()==QMouseEvent::MouseButtonPress && ((mouseEvent->buttons() & Qt::LeftButton)==Qt::LeftButton)) //do zoom on a mouse click
{
QRectF widgetRect(mouseEvent->pos().x() - 50, mouseEvent->pos().y() - 50, 100, 100); //build a rectangle around mouse cursor position
const QwtScaleMap xMap = plot->canvasMap(zoom->xAxis());
const QwtScaleMap yMap = plot->canvasMap(zoom->yAxis());
QRectF scaleRect = QRectF(
QPointF(xMap.invTransform(widgetRect.x()), yMap.invTransform(widgetRect.y())),
QPointF(xMap.invTransform(widgetRect.right()), yMap.invTransform(widgetRect.bottom())) ); //translate mouse rectangle to zoom rectangle
zoom->zoom(scaleRect);
}
}
I would like to display sample6 of the OptixSDK in a QGLWidget.
My application has only 3 QSlider for the rotation around the X,Y,Z axis and the QGLWidget.
For my understanding, paintGL() gets called whenever updateGL() is called by my QSlider or Mouseevents. Then I initialize a rotation matrix and apply this matrix to the PinholeCamera in order to trace the scene with new transformed cameracoordinates, right?
When tracing is finished i get the outputbuffer and use it draw the pixels with glDrawPixels(), just like in GLUTdisplay.cpp given in the OptiX framework.
But my issue is that the image is skewed/distorted. For example I wanted to display a ball, but the ball is extremley flatened, but the rotation works fine.
When I am zooming out, it seems that the Image scales much slower horizontally than vertically.
I am almost sure/hope that it has to do something with the gl...() functions that are not used properly. What am I missing? Can someone help me out?
For the completeness i post my paintGL() and updateGL() code.
void MyGLWidget::initializeGL()
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
m_scene = new MeshViewer();
m_scene->setMesh( (std::string( sutilSamplesDir() ) + "/ball.obj").c_str());
int buffer_width, buffer_height;
// Set up scene
SampleScene::InitialCameraData initial_camera_data;
m_scene->setUseVBOBuffer( false );
m_scene->initScene( initial_camera_data );
int m_initial_window_width = 400;
int m_initial_window_height = 400;
if( m_initial_window_width > 0 && m_initial_window_height > 0)
m_scene->resize( m_initial_window_width, m_initial_window_height );
// Initialize camera according to scene params
m_camera = new PinholeCamera( initial_camera_data.eye,
initial_camera_data.lookat,
initial_camera_data.up,
-1.0f, // hfov is ignored when using keep vertical
initial_camera_data.vfov,
PinholeCamera::KeepVertical );
Buffer buffer = m_scene->getOutputBuffer();
RTsize buffer_width_rts, buffer_height_rts;
buffer->getSize( buffer_width_rts, buffer_height_rts );
buffer_width = static_cast<int>(buffer_width_rts);
buffer_height = static_cast<int>(buffer_height_rts);
float3 eye, U, V, W;
m_camera->getEyeUVW( eye, U, V, W );
SampleScene::RayGenCameraData camera_data( eye, U, V, W );
// Initial compilation
m_scene->getContext()->compile();
// Accel build
m_scene->trace( camera_data );
m_scene->getContext()->launch( 0, 0 );
// Initialize state
glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(0, 1, 0, 1, -1, 1 );
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glViewport(0, 0, buffer_width, buffer_height);
}
And here is paintGL()
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
float3 eye, U, V, W;
m_camera->getEyeUVW( eye, U, V, W );
SampleScene::RayGenCameraData camera_data( eye, U, V, W );
{
nvtx::ScopedRange r( "trace" );
m_scene->trace( camera_data );
}
// Draw the resulting image
Buffer buffer = m_scene->getOutputBuffer();
RTsize buffer_width_rts, buffer_height_rts;
buffer->getSize( buffer_width_rts, buffer_height_rts );
int buffer_width = static_cast<int>(buffer_width_rts);
int buffer_height = static_cast<int>(buffer_height_rts);
RTformat buffer_format = buffer.get()->getFormat();
GLvoid* imageData = buffer->map();
assert( imageData );
switch (buffer_format) {
/*... set gl_data_type and gl_format ...*/
}
RTsize elementSize = buffer->getElementSize();
int align = 1;
if ((elementSize % 8) == 0) align = 8;
else if ((elementSize % 4) == 0) align = 4;
else if ((elementSize % 2) == 0) align = 2;
glPixelStorei(GL_UNPACK_ALIGNMENT, align);
gldata = QGLWidget::convertToGLFormat(image_data);
NVTX_RangePushA("glDrawPixels");
glDrawPixels( static_cast<GLsizei>( buffer_width ), static_cast<GLsizei>( buffer_height ),gl_format, gl_data_type, imageData);
// glDraw
NVTX_RangePop();
buffer->unmap();
}
After hours of debugging, I found out that I forgot to set the Camera-parameters right, it had nothing to go to with the OpenGL stuff.
My U-coordinate, the horizontal axis of view plane was messed up, but the V,W and eye coordinates were right.
After I added these lines in initializeGL()
m_camera->setParameters(initial_camera_data.eye,
initial_camera_data.lookat,
initial_camera_data.up,
initial_camera_data.vfov,
initial_camera_data.vfov,
PinholeCamera::KeepVertical );
everything was right.
I want to draw plane that picture.
now I try vertex buffer and DrawPrimitive is D3DPT_LINESTRIP. but not effect I want.
so any way more than effective that???
please give me some advice. thank you.
This could be an option, is not the optimal but would achive that grid
void DrawGrid (float32 Size, CColor Color, int32 GridX, int32 GridZ)
{
// Check if the size of the grid is null
if( Size <= 0 )
return;
// Calculate the data
DWORD grid_color_aux = Color.GetUint32Argb();
float32 GridXStep = Size / GridX;
float32 GridZStep = Size / GridZ;
float32 halfSize = Size * 0.5f;
// Set the attributes to the paint device
m_pD3DDevice->SetTexture(0,NULL);
m_pD3DDevice->SetFVF(CUSTOMVERTEX::getFlags());
// Draw the lines of the X axis
for( float32 i = -halfSize; i <= halfSize ; i+= GridXStep )
{
CUSTOMVERTEX v[] =
{ {i, 0.0f, -halfSize, grid_color_aux}, {i, 0.0f, halfSize, grid_color_aux} };
m_pD3DDevice->DrawPrimitiveUP( D3DPT_LINELIST,1, v,sizeof(CUSTOMVERTEX));
}
// Draw the lines of the Z axis
for( float32 i = -halfSize; i <= halfSize ; i+= GridZStep )
{
CUSTOMVERTEX v[] =
{ {-halfSize, 0.0f, i, grid_color_aux}, {halfSize, 0.0f, i, grid_color_aux} };
m_pD3DDevice->DrawPrimitiveUP( D3DPT_LINELIST,1, v,sizeof(CUSTOMVERTEX));
}
}
The CUSTOMVERTEX struct:
struct CUSTOMVERTEX
{
float32 x, y, z;
DWORD color;
static unsigned int getFlags()
{
return D3DFVF_CUSTOMVERTEX;
}
};
Note: Is only a grid with lines, so you need to draw a solid plane, in order to get a look like result as you want.
You can use DrawPrimitive with D3DPT_TRIANGLESTRIP for a plane. Then draw the indexed lines after with D3DPT_LINELIST with a depth bias. This way, even if they lie on the plane, you won't get any z-fighting.
I will introduce you a book Introduction to 3D programming with DirectX,it has a great
detail on how to do this in Chapter 8,Section 4.
I just drawn grid lines in the QGraphicsView on its background
drawbackground(QPainter *painter, const QRectF &rect)
{
QVarLengthArray<QLineF, 100> linesX;
for (qreal x = left; x < sceneRect.right(); x += gridInterval )
{
linesX.append(QLineF(x, sceneRect.top(), x, sceneRect.bottom()));
}
QVarLengthArray<QLineF, 100> linesY;
for (qreal y = top; y < sceneRect.bottom(); y += gridInterval ){
linesY.append(QLineF(sceneRect.left(), y, sceneRect.right(), y));
}
painter->drawLines(linesX.data(), linesX.size());
painter->drawLines(linesY.data(), linesY.size());
}
and im scaling the view by
void
ViewPort::zoomIn()
{
zoom(qreal(1.2));
}
void
ViewPort::zoomOut()
{
zoom(1 / qreal(1.2));
}
void
ViewPort::zoom(qreal scaleFactor)
{
qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
if (factor < 1 || factor > 100)
return;
scale(scaleFactor, scaleFactor);
}
now the scen has plenty of items that i have to scale but i need to ignore the grid lines i have drawn on the graphicsView drawBackground .
how i can ignore the scale transformation of gridLines.?
i tried QPainter::resetTransform() but in vain ..
If you aggregate the lines into an object which you derive from QGraphicsItem and add the item to the scene, you can then set the flag QGraphicsItem::ItemIgnoresTransformations, to stop it responding to scaling and other transformations.