#include "xy.h"
#include <intrin.h>
#include <limits>
#include "wutils.h"
#include "datareader.h"
void Range::reset() {
init(std::numeric_limits<float>::infinity(),-std::numeric_limits<float>::infinity());
}
bool isnanorinf(float v) {
return !~(*(int*)&v>>23&0xFF);
}
bool Range::expand(float _a,float _e) {
bool ret=0;
if (!isnanorinf(_a) && a>_a) {a=_a; ret=true;}
if (!isnanorinf(_e) && e<_e) {e=_e; ret=true;}
return ret;
}
BYTE Range::test(const RANGE&r) {
BYTE ret=0;
if (a>r.a) ret|=EXPAND;
if (a<r.a) ret|=SHRINK;
if (e<r.e) ret|=EXPAND;
if (e>r.e) ret|=SHRINK;
return ret;
}
BYTE Range::set(const RANGE&r,BYTE allow) {
BYTE ret=test(r);
if (allow&ret) *(RANGE*)this=r;
return ret; // kann gleichzeitig EXPAND und SHRINK haben
}
BYTE Range::set2(const RANGE&r,ALLOW allow) {
BYTE ret;
if (allow==SHRINK) {
float d=r.e-r.a;
Range t(round2(r.a,d,false),round2(r.e,d,true)); // Vergrößerten Testbereich erstellen
ret=test(t);
if (allow&ret) *(RANGE*)this=t; // Diesen nehmen
}else{
ret=test(r);
if (allow&ret) {
float d=r.e-r.a;
a=round2(r.a,d,false); // Zielbereich immer etwas größer als der Ausgangsbereich
e=round2(r.e,d,true);
}
}
return ret;
}
/* Plotdaten können in allgemeiner Form übergeben werden:
- Datentyp int8_t, int16_t, int32_t, int64_t, float, double,
bool, uint8_t, uint16_t, Funktionszeiger
getrennt für X und Y
- XY-Daten getrennt oder verschachtelt
*/
/*
void test() {
static const float data[]={1,2,3,4};
DatareaderN<double> dr(data,DatareaderN<double>::F32,sizeof(float));
double t=dr.get();
for (int i=0; i<elemof(data); i++) printf("%f",dr());
}
*/
/*** Plot ***/
void Plot::init() {
if (sr.typeX>=10) sr.typeX=8; // "float" als Vorgabe für Zeit
if (sr.typeY>=10) sr.typeY=8; // "float" als Vorgabe für Werte
if (!sr.sa) {
sr.sa=new SAMPLES;
sr.sa->ptr.v=0;
sr.sa->inc=DatareaderN<float>::getarrayinc(DatareaderN<float>::typ(sr.typeY));
if (sr.flags&1) sr.sa->inc+=DatareaderN<float>::getarrayinc(DatareaderN<float>::typ(sr.typeX));
sr.sa->siz=3600;
sr.alloc|=1; // Dieser Plot hat alloziert
}
if (!sr.sa->ptr.v) {
if (sr.sa->siz<10) sr.sa->siz=3600;
sr.sa->ptr.b=new BYTE[sr.sa->siz*sr.sa->inc];
sr.sa->start=sr.sa->fill=0;
sr.alloc|=2; // Dieser Plot hat alloziert
}
s.points=new Gdiplus::PointF[sr.sa->siz]; // Problem: PolyPolyline unklar! Rückende X-Werte blöd!
s.pen=new Gdiplus::Pen(color,lineWidth);
sr.alloc|=8|4;
if (!sr.sx.f) sr.sx.f=1; // Nullfaktoren zu 1 machen
if (!sr.sy.f) sr.sy.f=1;
}
void Plot::done() { // Aufräumen der Speicherbereiche
if (sr.alloc&8) {
delete s.pen;
s.pen=0;
}
if (sr.alloc&4) {
delete s.points;
s.points=0;
}
if (sr.alloc&2) {
delete[] sr.sa->ptr.b;
sr.sa->ptr.b=0;
}
if (sr.alloc&1) {
delete sr.sa;
sr.sa=0;
}
sr.alloc=0;
}
Plot::Plot(XY*_parent,PLOT&plotinfo)
:rangeX(std::numeric_limits<float>::infinity(),-std::numeric_limits<float>::infinity())
,rangeY(std::numeric_limits<float>::infinity(),-std::numeric_limits<float>::infinity())
{
parent=_parent;
xscale=parent->getXScale(plotinfo.xscale);
yscale=parent->getYScale(plotinfo.yscale);
color=parent->getPlotColor(plotinfo.index);
*(PLOT*)this=plotinfo;
memset(&s,0,sizeof s);
init(); // Alle Puffer erzeugen, wenn nicht vorhanden
}
void Plot::onSize(Gdiplus::Graphics&g) {
}
// Nur für den Fall dass jeder Plot seine eigene Datenliste verwalten muss!
// Sonst wäre das Vorrücken von fill bzw. start falsch.
void Plot::putdata(FLEXDATA&srcptr) {
action a=ADD1;
UINT size=DatareaderN<float>::getarrayinc(DatareaderN<float>::typ(sr.typeY));
if (sr.flags&1) size+=DatareaderN<float>::getarrayinc(DatareaderN<float>::typ(sr.typeX));
SAMPLES&sb=*sr.sa;
BYTE*bp=sb.ptr.b+(sb.fill==sb.siz?sb.start:sb.fill)*sb.inc;
memcpy(bp,srcptr.cv,size); // Erforderliche Daten entnehmen und in zirkulären Puffer schreiben
srcptr.b+=size; // Beide Zeiger weiterrücken
if (sb.fill==sb.siz) { // Puffer voll? Dann wurde das älteste Sample überschrieben.
if (++sb.start==sb.siz) sb.start=0;
if (!(sr.flags&1)) sr.sx.o+=sr.sx.f; // Startzeit weiterrücken
a=SHIFT1;
}else ++sb.fill;
makePoly(a);
// s.check(*this);
}
void Plot::makePoly(action a) {
// DatareaderN<float> reader(sr.sa->ptr.cv,DatareaderN<float>::typ(sr.typeY));
bool exx=false,exy=false;
if (sr.flags&1) rangeX.reset();
rangeY.reset();
BYTE*bp=sr.sa->ptr.b;
for (UINT i=0,k=sr.sa->start;i<sr.sa->fill;i++) {
BYTE*q=bp+k*sr.sa->inc;
if (sr.flags&1) {
FLEXDATA p={q+sr.ofsX};
exx|=rangeX.expand(s.points[i].X=((Scalepair*)&sr.sx)->scale(DatareaderN<float>::getters[sr.typeX](p)));
}else s.points[i].X=((Scalepair*)&sr.sx)->scale((float)i);
FLEXDATA p={q+sr.ofsY};
exy|=rangeY.expand(s.points[i].Y=((Scalepair*)&sr.sy)->scale(DatareaderN<float>::getters[sr.typeY](p)));
if (++k==sr.sa->siz) k=0;
}
s.len=sr.sa->fill;
if (!(sr.flags&1)) {
rangeX.a=sr.sx.o;
rangeX.e=rangeX.a+(s.len-1)*sr.sx.f;
exx=true; // immer Expansion
}
if (exx && xscale->range.set2(rangeX)&Range::EXPAND) parent->needReposition=true;
if (exy && yscale->range.set2(rangeY)&Range::EXPAND) parent->needReposition=true;
}
void Plot::onPaint(Gdiplus::Graphics&g) {
g.TranslateTransform(xscale->O,0/*yscale->O*/);
g.ScaleTransform(xscale->F,1/*yscale->F*/);
g.DrawLines(s.pen,s.points,s.len);
g.ResetTransform();
}
Detected encoding: UTF-8 | 0
|