Seite 1 von 2

Qwt Kurven zeichnen

Verfasst: 16. Juni 2007 12:18
von peeter
Hallo Leute,
ich habe folgende Frage an euch, wie würdet ihr es realisieren, dass man aus einem Datenstrom, der jede Sekunde neu rein kommt und wo die einzelnen Daten schon vorliegen eine Kurve zeichnet bzw den neuen Teil anhängt? achso und eine skala für die einheiten würde auch noch dazu kommen...

ganz unten in der addData sind die einkommenden Daten, ich will die nord ost verteilung als x y darstellen....aktuell zeichnet er nur die fkt
xval = double(i) * 10.0 / double(Size - 1);
yval = sin(xval) * cos(3.0 * xval);
...und dies auch schon vorher, also nicht in echtzeit so wie ich es gerne hätte mit den daten aus dem datenstrom

wäre für jeden ratschlag oder hilfe sehr dankbar!!!

plot.h
#ifndef PLOT_H
#define PLOT_H
#include <qframe.h>
#include <qwt_scale_map.h>
#include <qwt_plot_curve.h>

class Plot : public QFrame
{
Q_OBJECT
public:
Plot(QWidget*parent);

protected:
#if QT_VERSION >= 0x040000
virtual void paintEvent(QPaintEvent *);
#endif
void drawContents(QPainter *p);
public:
void addData(const QString &, const QString &, const QString &,const QString &, const QString &);
private:
#if QT_VERSION >= 0x040000
enum {CurvCnt = 2};
#else
enum {CurvCnt = 1};
#endif
enum {Size = 27};


QwtPlotCurve crv[CurvCnt];

//
// Arrays holding the values
//
double xval[Size];
double yval[Size];
QwtScaleMap xMap;
QwtScaleMap yMap;
};


#endif


plo.cpp
#include <qapplication.h>
#include <qframe.h>
#include <qwt_scale_map.h>
#include <qwt_plot_curve.h>
#include <qwt_symbol.h>
#include <qcolor.h>
#include <qpainter.h>
#if QT_VERSION >= 0x040000
#include <qpaintengine.h>
#endif
#include <math.h>
#include <QString>
#include "Plot.h"
#include "Plot.moc"

const int Size = 27;

Plot::Plot(QWidget *parent)
{

int i;
setWindowTitle(tr("Wild_ABS"));
setMinimumSize(160, 160);
resize(480, 220);
xMap.setScaleInterval(-0.5, 10.5);
yMap.setScaleInterval(-1.1, 1.1);


//
// Werte übertragen
//
for(i=0; i<Size;i++)
{ xval = double(i) * 10.0 / double(Size - 1);
yval = sin(xval) * cos(3.0 * xval);
}

//
// define curve styles
//
QwtSymbol sym;
i = 0;


#if QT_VERSION >= 0x040000
crv.setPen(QColor(Qt::darkBlue));
crv.setStyle(QwtPlotCurve::Lines);
crv[i].setRenderHint(QwtPlotItem::RenderAntialiased);
i++;
#endif


//
// attach data
//
for(i=0;i<CurvCnt;i++)
crv[i].setRawData(xval,yval,Size);
}

#if QT_VERSION >= 0x040000
void Plot::paintEvent(QPaintEvent *event)
{


QFrame::paintEvent(event);

QPainter painter(this);
painter.setClipRect(contentsRect());
drawContents(&painter);
}
#endif


//
// REDRAW CONTENTS
//
void Plot::drawContents(QPainter *painter)
{

int i;

QRect r = contentsRect();

//
// draw curves
//
for (int i=0;i<CurvCnt;i++)
{
xMap.setPaintInterval(r.left(), r.right());
yMap.setPaintInterval(r.top(), r.bottom());

#if QT_VERSION >= 0x040000
const QPaintEngine *pe = painter->device()->paintEngine();
if (pe->hasFeature(QPaintEngine::Antialiasing) )
{
painter->setRenderHint(QPainter::Antialiasing,
crv[i].testRenderHint(QwtPlotItem::RenderAntialiased) );
}
#endif
crv[i].draw(painter, xMap, yMap, r);

}
}
void Plot::addData(const QString &marker, const QString &north, const QString &east, const QString &hight, const QString &satcount){
printf("\n%.10s:%.5s:%.5s:%.5s:%.5s%",marker.toLatin1().data(), north.toLatin1().data(),east.toLatin1().data(),hight.toLatin1().data(),satcount.toLatin1().data());
}


Verfasst: 16. Juni 2007 15:10
von Uwe
Mit Qwt geht das eigentlich ganz einfach, aber soweit ich sehe hast Du Dir Deinen Code irgendwie aus den Qwt Sourcen zusammenkopiert. Ich würde Dir dagegen empfehlen Qwt zu verwenden, anstatt es zu verwursten - sollte zumindest sehr viel einfacher sein. Also:

1) Besorge Dir Qwt 5.0.2 und installier es sauber auf Deinem Rechner.
2) Schau Dir mal das realtime Beispiel an. Das zeigt u.a. wie man inkrementell plotten kann. Dort findest Du eine Klasse IncrementalPlot, die im Prinzip das macht was Du willst.

"Inkremetelles Plotten" bedeutet nur neu hinzugekommen Punkte zu zeichen. Hat man z.B. eine Kurve mit 1000 Punkten zu der alle 100 ms 10 dazukommen, kann man sich vorstellen, daß man damit seht viel höhere Bildwiederholraten hinbekommt.
2 Anmerkungen dazu:

a) Wenn Du das realtime Beispiel mit Qt3 und Qt4 ausführst, wirst Du feststellen das Qt3 sehr viel schneller ist. Das hat damit zu tun, daß Qt4 alles im Hintergund über einen "backing store" (ein pixmap) führt, um semi transparente Widgets zu unterstützen. D.h inkrementelles Zeichnen ist mit Qt4 nicht möglich ! (Ich habe das Problem auf einem Qt Tag mal angesprochen, mußte aber erkennen, daß TrollTech darauf setzt, daß sich solche Problem durch immer schnellere Hardware erledigt.)

b) Schau Dir erst einmal das data_plot Beispiel an. Dort werden zwei Kurven von jeweils 200 Punkten gezeichnet. Über eine SpinBox kannst Du ein Timer Intervall verändern, um ein Gefühl dafür zu bekommen, welche Bildwiederholungsraten auf Deinem System möglich sind. Eventuell benötigst Du ja gar kein inkrementelles Zeichen.

HTH,
Uwe

Verfasst: 17. Juni 2007 17:54
von peeter
danke uwe für die zeit mir den hinweis mit dem realtime plot zu geben...
leider habe ich das bsp noch nicht zu laufen bekommen, aufgrund eines [info] fehlers der leider weiter unbegründet bleibt im compiler,exe wird erzeugt wirft dann aber ein 0xc00000005 fehler, daher habe ich mir erstmal den code angeschaut und denke, dass ich einfach nur meine x und y daten an eine der appends übergeben muss, sicherlich die appendData methode....was meinst du dazu?

...
void CurveData::append(double *x, double *y, int count)
{
int newSize = ( (d_count + count) / 1000 + 1 ) * 1000;
if ( newSize > size() )
{
d_x.resize(newSize);
d_y.resize(newSize);
}

for ( register int i = 0; i < count; i++ )
{
d_x[d_count + i] = x;
d_y[d_count + i] = y;
}
d_count += count;
}

int CurveData::count() const
{
return d_count;
}

int CurveData::size() const
{
return d_x.size();
}

const double *CurveData::x() const
{
return d_x.data();
}

const double *CurveData::y() const
{
return d_y.data();
}

IncrementalPlot::IncrementalPlot(QWidget *parent):
QwtPlot(parent),
d_data(NULL),
d_curve(NULL)
{
setAutoReplot(false);
}

IncrementalPlot::~IncrementalPlot()
{
delete d_data;
}

void IncrementalPlot::appendData(double x, double y)
{
appendData(&x, &y, 1);
}

void IncrementalPlot::appendData(double *x, double *y, int size)
{
if ( d_data == NULL )
d_data = new CurveData;

if ( d_curve == NULL )
{
d_curve = new QwtPlotCurve("Test Curve");
d_curve->setStyle(QwtPlotCurve::NoCurve);
d_curve->setPaintAttribute(QwtPlotCurve::PaintFiltered);

const QColor &c = Qt::white;
d_curve->setSymbol(QwtSymbol(QwtSymbol::XCross,
QBrush(c), QPen(c), QSize(5, 5)) );

d_curve->attach(this);
}

d_data->append(x, y, size);
d_curve->setRawData(d_data->x(), d_data->y(), d_data->count());
#ifdef __GNUC__
#endif

const bool cacheMode =
canvas()->testPaintAttribute(QwtPlotCanvas::PaintCached);

canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
d_curve->draw(d_curve->dataSize() - size, d_curve->dataSize() - 1);
canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, cacheMode);
}
...

Ich habe dasselbe Problem beim plotten...

Verfasst: 21. Juni 2007 16:04
von TheMetalManiac
Hallo!

Auch ich bin ein Newbie und möchte gerne einen QWTPlot benutzen um die Daten von einer Hardware graphisch auszugeben (Praktikum an der Uni).

Das Problem <0xc....5> habe ich auch...Liegt das jetzt an QT?

Habe schon einige Foren durchsucht und bin immer wieder auf eine bestimmte Person gestoßen...UWE.

Hallo Uwe...

Ich kann alle deine Plots erstellen (mingw32 auf winxp) bis auf gerade die relevanten Data_Plot und Realtime_plot.

Ich habe nun schon einige Tage den Realtime_plot- Code durch geschaut...btw: ein paar kommentare wären super :-) (sowas wie nice blue bei der farbauswahl hilft da nicht viel ;-)).
Bitte versteh mich in dem Punkt nicht falsch...natürlich will ich selber QWT lernen!!! Die ersten Beispiele sind ja auch ganz anschaulich...aber wenn es dann ans eingemachte geht, fehlt mir da der Überblick. Daher wären Kommentare echt eine riesen Hilfe.

Sobald ich den Realtime_plot einmal ausgeführt habe, könnte man durch Veränderungen am Code schnell seine bisherigen verständlichlücken schließen.

Noch eine wichtige Frage: In unserem Praktikum müssen wir mindestens 5 Plots parallel laufen lassen. Da ich in einigen Foren etwas über schlechtere Performanz des Plots gelesen habe, wäre es gut zu wissen ob QWT bzw. QT das überhaupt schafft.

Herzlichen Dank schonmal für deine Mühe und ich finde es genial, dass du (Uwe) sämtliche Foren durchsuchst und fragen zu den Plots beantwortest!!!

TheMetalManiac

Re: Ich habe dasselbe Problem beim plotten...

Verfasst: 21. Juni 2007 23:15
von Uwe
Das Problem <0xc....5> habe ich auch...Liegt das jetzt an QT?
Wie hast Du denn die Qt Bibliothek gebaut (statisch/dynamisch) ? Ist das Programm eines der Qwt Beispiele und hast Du irgendwelche Änderungen an den Dateien aus dem Qwt Paket vorgenommen ?
Ich habe nun schon einige Tage den Realtime_plot- Code durch geschaut
In dem Beispiel geht es eigentlich nur darum zu zeigen, wie man mit Hilfe von QwtPlotCurve::drawCurve nur hinzukommende Punkte zeichnet. Das ist aber eine sehr spezielle Optimierung, die man nur selten benötigt ( und mit Qt4 ohnehin nicht mehr viel bringt ).
Noch eine wichtige Frage: In unserem Praktikum müssen wir mindestens 5 Plots parallel laufen lassen. Da ich in einigen Foren etwas über schlechtere Performanz des Plots gelesen habe, wäre es gut zu wissen ob QWT bzw. QT das überhaupt schafft.
Das hängt davon ab, wie viele Punkte Deine Kurven haben und wie oft Du die pro Sekunde neuzeichnen willst/musst. Um einen Eindruck über die Leistungsfähigkeit Deines Systems zu gewinnen, schau Dir das data_plot Beispiel an.

Uwe

Verfasst: 23. Juni 2007 21:14
von peeter
Uwe ich danke dir für deine Hilfe im Forum, bei mir läuft soweit alles und es sieht auch noch gut aus^^
ich habe da nur ein problem. ich habe mich an die vorlage des real_time plot gehalten und man hat dort die möglichkeit die punkte, durch Linien, miteinander zu verbinden. Leider tut er das immer erst nachdem man einen manuellen repaint verursacht hat(fenster größer ziehen oder so)
wie bekomme ich es hin, dass er nach jedem punkt einen automatischen repaint macht, direkt nach dem draw der punkte geht es leider nicht, habe es bis jetzt mit repaint() und update() probiert,nur leider ohne erfolg...wäre für deine hilfe sehr dankbar. Ich könnte dir auch einmal den kompletten quelltext schicken
mfg

Verfasst: 24. Juni 2007 10:35
von Uwe
http://qwt.sourceforge.net/class_qwt_pl ... d0d7633c4b

Uwe

PS: Support gehört zu den Aufgaben eines Maintainers. Zu den Pflichten eines Anwenders gehört es aber zumindest zu versuchen eine Aufgabe selber zu lösen. Wer QwtPlot::replot nicht kennt, hat das im Fall von Qwt sicher nicht getan.

Problem <0xc.....5>

Verfasst: 24. Juni 2007 12:27
von TheMetalManiac
Hallo nochmal.

Die QT Bibliothek habe ich über qmake kompeliert.
Gerade die beiden Beispiele Data_plot und Realtime_Plot spucken den Fehler aus (beide Dateien sind unverändert). Ich arbeite mit WinXP und kompiliere mit mingw32.

Es scheint ja ein Laufzeitfehler zu sein.

Wenn der Peeter das hinbekommen hat, wäre es super, wenn er schreiben könnte wie er diesen Laufzeitfehler behoben hat. Vllt. muss ich die QT Bibliothek doch noch anders kompelieren??

Also, nochmals herzlichen Dank für die Unterstützung hier im Forum,

TheMetalManiac

Verfasst: 24. Juni 2007 14:55
von peeter
lol danke uwe, manchmal liegt die lsg doch so nah^^
habe es nämlich in alter java manier mit update(), repaint(), updateLayout() und so probiert^^
achso uwe kannst du mir vllt noch verraten, ob man dieses linien zeichnen bei bestimmten punkten unterdrücken kann? das Zeichnen soll nicht passieren, wenn zwei punkte einen größeren abstand haben, als vorgeschrieben, ansonsten soll immer der neue mit dem nächst neuen Punkt verbunden werden...

@metal ich schreibe dir morgen rein was ich alles gemacht habe, muss jetzt mal los

Verfasst: 25. Juni 2007 22:20
von butze
hi!

ich stand bis vor 20 min vor dem selben Problem.

Allerdings konnte ich es dank der Tips hier beheben, hab aber noch einige Fragen.

Zunächst. Problem lag in der *.pro Datei. Laut Uwe soll man die data_plot.pro benutzen (nicht includen- sorry uwe, falsch formuliert :) ), die examples.pri beinhaltet. examples.pri wiederum included qwtconfig.pri.
Zunächst habe ich anstelle der include Befehle die Inhalte der .pri Dateien in eine einzige .pro Datei (data_plot.pro) kopiert
Dabei enstand folgendes:

Code: Alles auswählen


[b]#qwtconfig.pri start[/b]

######################################################################
# Install paths
######################################################################

unix {
    INSTALLBASE    = /usr/local/qwt
}

win32 {
    INSTALLBASE    = C:/Qwt
}

target.path    = $$INSTALLBASE/lib
headers.path   = $$INSTALLBASE/include
doc.path       = $$INSTALLBASE/doc

######################################################################
# qmake internal options
######################################################################

CONFIG           += qt     # Also for Qtopia Core!
CONFIG           += warn_on
CONFIG           += thread

######################################################################
# release/debug mode
# The designer plugin is always built in release mode.
# If want to change this, you have to edit designer/designer.pro.
######################################################################

CONFIG           += release     # release/debug

######################################################################
# Build the static/shared libraries.
# If QwtDll is enabled, a shared library is built, otherwise
# it will be a static library.
######################################################################

CONFIG           += QwtDll

######################################################################
# QwtPlot enables all classes, that are needed to use the QwtPlot 
# widget. 
######################################################################

CONFIG       += QwtPlot

######################################################################
# QwtWidgets enables all classes, that are needed to use the all other
# widgets (sliders, dials, ...), beside QwtPlot. 
######################################################################

CONFIG     += QwtWidgets

######################################################################
# If you want to display svg imageson the plot canvas, enable the 
# line below. Note that Qwt needs the svg+xml, when enabling 
# QwtSVGItem.
######################################################################

#CONFIG     += QwtSVGItem

######################################################################
# If you have a commercial license you can use the MathML renderer
# of the Qt solutions package to enable MathML support in Qwt.
# So if you want this, copy qtmmlwidget.h + qtmmlwidget.cpp to
# textengines/mathml and enable the line below.
######################################################################

#CONFIG     += QwtMathML

######################################################################
# If you want to build the Qwt designer plugin, 
# enable the line below.
# Otherwise you have to build it from the designer directory.
######################################################################

CONFIG     += QwtDesigner

######################################################################
# If you want to auto build the examples, enable the line below
# Otherwise you have to build them from the examples directory.
######################################################################

#CONFIG     += QwtExamples

[b]#qwtconfig.pri ende

#examples.pri start
[/b]
# -*- mode: sh -*- ################################################
# Qwt Widget Library
# Copyright (C) 1997   Josef Wilgen
# Copyright (C) 2002   Uwe Rathmann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the Qwt License, Version 1.0
###################################################################

include( ../../qwtconfig.pri )

TEMPLATE     = app

MOC_DIR      = moc
OBJECTS_DIR  = obj
INCLUDEPATH += ../../src
DEPENDPATH  += ../../src

unix:LIBS        += -L../../lib -lqwt

win32:QwtDll {
    DEFINES    += QT_DLL QWT_DLL
}

win32-msvc:LIBS  += ../../lib/qwt5.lib
win32-msvc.net:LIBS  += ../../lib/qwt5.lib
win32-msvc2005:LIBS += ../../lib/qwt5.lib
win32-g++:LIBS   += -L../../lib -lqwt

[b]#examples.pri ende

#data_plot.pro start[/b]

TARGET       = data_plot

HEADERS = \
    data_plot.h

SOURCES = \
     data_plot.cpp \
     main.cpp

[b]#data_plot.pro ende[/b]

Diesen ganzen Konstrukt habe ich dann etwas gekürzt zu:

Code: Alles auswählen

CONFIG += qt \
		  warn_on \
		  thread \
		  debug_and_release \
		  QwtDll \
		  #QwtPlot \
		  #QwtWidgets \
		  #QwtSVGItem \
		  #QwtMathML \
		  #QwtDesigner \
		  #QwtExamples 

TEMPLATE     = app

MOC_DIR      = moc
OBJECTS_DIR  = obj
INCLUDEPATH += %QWTDIR%\include    #so heißt meine Systemvariable zum QWT Ordner
DEPENDPATH  += %QWTDIR%\include

win32:QwtDll {
    DEFINES    += QT_DLL QWT_DLL
}

#win32-msvc:LIBS  += ../../lib/qwt5.lib
#win32-msvc.net:LIBS  += ../../lib/qwt5.lib
#win32-msvc2005:LIBS += ../../lib/qwt5.lib
win32-g++:LIBS   += -L../../lib -lqwt


TARGET = dataPlot
  
HEADERS = data_plot.h
   
SOURCES = data_plot.cpp \
 	      main.cpp
  
...und es läuft.

Jetzt kommt meine Frage:
Wenn ich die Zeile mit "QwtDll " oder den Abschnitt mit "win32:QwtDll {
DEFINES += QT_DLL QWT_DLL
}" herausnehme kommt der o.g. Fehler beim Starten der *.exe.

Was bedeuten diese Zeilen?

Darüber hinaus: wozu brauche ich #QwtPlot und #QwtWidgets ??

Verfasst: 25. Juni 2007 23:13
von Uwe
Wie Du richtig erkannt hast, geht es einzig um folgende Zeile:

DEFINES += QT_DLL QWT_DLL

Damit werden die "__declspec(dllimport)" Deklarationen scharf gemacht, die man benötigt, wenn man Qt bzw. Qwt DLLs hat (siehe qwt_global.h).

Uwe

PS: Ein '#' ist der Beginn eines Kommentars.
PS2: Ich habe vielleicht empfohlen eine QMake Projekt Datei eines Qwt Beispiels als Vorlage zu nehmen, aber ganz bestimmt nicht sie irgendwie zu includieren.

Verfasst: 26. Juni 2007 13:43
von butze
hi!

@ uwe: das bringt mich nun ehrlich gesagt nicht viel weiter, da ich die Zeilen immer noch nicht verstehe

qmake variable reference sagt:

Code: Alles auswählen

DEFINES

qmake adds the values of this variable as compiler C preprocessor macros (-D option).

For example:
 DEFINES += USE_MY_STUFF QT_DLL
Wozu hätten denn nun die QwtPlot und QwtWidgets unter CONFIG gemacht, wenn ich die nicht auskommentiert hätte?


Für alle, die genau das Problem haben, eine bei mir funktionierende pro Datei im schönen Format:

Code: Alles auswählen

TEMPLATE = app                  # erstelle QT-Anwendung

TARGET = PlotBeispiel           # Name der erstellten *.exe Datei setzen

CONFIG += qt \                  # Compiler soll QT benutzen
          warn _on \            # moeglichst viele Compiler-Meldungen anzeigen
          debug_and_release \   # im debug und release modus compilieren
          console \             # Ausgaben werden von der QApp auf die Console weitergeleitet
          thread \              # aktiviere Threading
          QwtDll \              # Compiler soll QWT benutzen
		  
MOC_DIR = moc                   # speichere Meta-Object-Files in Ordner moc

OBJECTS_DIR = obj               # speichere .o Files im obj Ordner
		  
DEPENDPATH += . save \          # suche hier, um abhaengige .h Dateien aufzuslösen
              %QWTDIR%\include  # (to resolve dependencies)
			  
INCLUDEPATH += . save \         # Pfade , in dem bei #include gesucht wird
               %QWTDIR%\include

win32:QwtDll {                  # aktiviere qwt dll Deklarationen
      DEFINES  += QT_DLL QWT_DLL
}


#input der eigenen Headers
HEADERS += src/data_plot.h

#input der eigenen Sources
SOURCES += src/main.cpp \
           src/data_plot.cpp
	       
#input der mit dem Designer erstellen Files
#FORMS     += #name.ui    

#Ressources für Icons etc.
#RESOURCES += name.qrc

#input der benutzten Dlls
win32-g++:LIBS += "./save/libqwt5.a" \

Verfasst: 26. Juni 2007 14:54
von Uwe
QwtWidgets, QwtPlot und QwtDll sind Variablen mit den konfiguriert werden kann, wie Qwt gebaut werden soll. Sie sind einzig für den Qwt internen Build Prozess von Bedeutung und haben im qmake File der Anwendung natürlich auch keine Wirkung.

Du kannst also Dein Project File nochmal verbessern indem Du Zeilen mit QwtDll rauswirsfst und nur folgende Zeile stehen lässt:

DEFINES += QT_DLL QWT_DLL

Uwe

Verfasst: 26. Juni 2007 15:37
von butze
wenn ich "QwtDll \ # Compiler soll QWT benutzen " unter config rausnehme bekomme ich wieder den Fehler :(

die Zeile mit DEFINES blieb aber unangetastet drin

Verfasst: 26. Juni 2007 16:04
von Uwe
Du mußt natürlich auch die "win32:QwtDll" Klammer rausnehmen ( nicht die Zeile zwischen der Klammer ).

Anstelle von "try und error" wäre es sicher hilfreich auch mal die qmake Dokumentation anzuschauen um zu verstehen, was die jeweiligen Zeilen bedeuten.

Uwe