Source file: /~heha/ewa/Ofen/prozess.zip/msvc/o1/plot.cpp

#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-80