Source file: /~heha/ewa/Ofen/prozess.zip/msvc/o1/xy.h

#pragma once
#include "plot.h"
#include "vector.h"
#include <gdiplus.h>

char round125(float&v,bool up);	// v auf ein Vielfaches von 1, 2 oder 5 (bezüglich l) runden
float round2(float v,float l, bool up);	// v auf 1-2 signifikante Digits runden

struct Range:public RANGE{
 Range(float a, float e)	{init(a,e);}
 Range()			{reset();}
 void init(float _a, float _e)	{a=_a; e=_e;}
 void reset();			// {+Inf,-Inf} -> invalid
 bool inside(float v) const	{return a<=v && v<=e;}
 float length() const		{return e-a;}
 bool isRegular() const		{return length()>0;}	// Echtes Intervall
 bool isValid() const		{return length()>=0;}	// Echtes oder Null-Intervall
 bool expand(float v)		{return expand(v,v);}
 bool expand(float,float);
 bool expand(const RANGE&r)	{return expand(r.a,r.e);}	// r muss ein gültiger Bereich sein (oder nicht?)
 enum ALLOW{
  EXPAND=1,
  SHRINK=2,
 };
 BYTE test(const RANGE&);
 BYTE set(const RANGE&,BYTE allow=EXPAND);
 BYTE set2(const RANGE&,ALLOW allow=EXPAND);	// wie set() jedoch Expansion/Shrinken in größeren Sprüngen
};

struct Label{
 const char*string;
 float position;
 Gdiplus::RectF box;
//  int priority;	// bspw. 99 für kalkulierte Labels, 0 für Anwender-Labels, 1 für Achsenenden
};

class XY;
class Plot;

struct Scalepair:public SCALEPAIR {
 float scale(float x) const	{return x*f+o;}
 float unscale(float X) const	{return (X-o)/f;}
 SCALEPAIR&combine(const SCALEPAIR&b);	// Neues Scalepair für nicht-kommutative Hintereinanderausführungen mehrerer Skalierungen
 SCALEPAIR&operator*(const SCALEPAIR&b) {return combine(b);}
 SCALEPAIR&operator~();		// invertiertes SCALEPAIR liefern
};

class Scale:public SCALE{
public:
 Range range;
 Rect rc;
 Scale(XY*parent,UINT side,char*name=0);
 Scale(XY*parent,SCALE&scale);
 ~Scale();
	// left+topdown/top+leftright/right+topdown/bottom+leftright/left+downup/top+rightleft/right+downup/bottom+rightleft
		// Bit 0: X- oder Y-Ausrichtung
		// Bit 1: links/oben (0) oder rechts/unten (1)
		// Bit 2: nach rechts/unten wachsend (0) oder umgekehrt (1)
		// Bit 3: (Nur Y-Achse) Vertikal statt horizontal stapeln
		// Bit 4: Y-Achse: Digital: Name waagerecht, feste Höhe
		//	  X-Achse: Zeit: Skalenteilung in Stunden:Minuten:Sekunden
		// Bit 5: logarithmisch (nicht zusammen mit Digital)
 	// Anfang, Ende (darf nie gleich sein, sonst ÷0-Fehler!)
 float preci;	// Präzision = sinnvolle untere Tick-Grenze, <=0 = keine Grenze
 Gdiplus::Font*font[2];	// Schrift der Skaleneinteilung und der Achsenbezeichnung
 Gdiplus::Color color[2];// Farbe der Skaleneinteilung (Striche und Text) und der Achsenbezeichnung
 Gdiplus::Brush*brush[2];	// Pinsel für Schrift
 std::vector<Label> labels;	// Feste Labels (Marken) in der Skale
 std::vector<Plot*> plots;	// Zugeordnete Plots (für Autoskalierung)
 XY*parent;
 float F,O;	// Faktor, Offset (Großbuchstaben = Pixelbereich, Kleinbuchstaben = Anwenderbereich)
private:
 int Length() const {int ret=(side&1?rc.height():rc.width())-1;if (side&4) ret=-ret; return ret;}	// Länge der Skale in Pixel; negativ wenn rückwärts laufend
 int Start() const {return side&4?rc[side&1|2]-1:rc[side&1];}	// Koordinate des Skalenanfangs (zu "a" gehörig)
 std::vector<Label> ticks;	// Berechnung bei onSize(), distributeTicks()
 Gdiplus::SizeF numberExtent;	// Berechnung bei needSpace()
 static const char ticklen=5;
public:
 void calcFO() {F=(float)Length()/((Range*)&range)->length(); O=(float)Start()-range.a/F;}	// Faktor + Offset neu berechnen (Bereichsänderung oder Größenänderung)
 float scale(float x) const {return x*F+O;}
 float unscale(float X) const {return (X-O)/F;}
 void setRange(float _a, float _e) {range.a=_a; range.e=_e; calcFO();}
 void distributeTicks(Gdiplus::Graphics&);
 void tickstringformat(Gdiplus::StringFormat&);
 void tickposition(float,Gdiplus::PointF[2]);
 void namestringformat(Gdiplus::StringFormat&);
 void nameposition(Gdiplus::Graphics&,Gdiplus::PointF&);
 bool addTick(Gdiplus::Graphics&,float v,char nk);
 void onPaint(Gdiplus::Graphics&);
 void onSize(Gdiplus::Graphics&);
 struct NEED{
  int w;	// X: Ungefähre Breite; Y: Ungefähre Höhe; Eingangsparameter
  int h,l,r;	// X: Höhe, linker Überhang, rechter Überhang, oder Y: Breite, oberer Überhang, unterer Überhang
 };
 void needSpace(Gdiplus::Graphics&,NEED&);
};

class Plot:public PLOT{
 void init();
 void done();
 XY*parent;
 Scale*xscale,*yscale;
 Gdiplus::Color color;
 wchar_t marker;
 struct stroke{
  Gdiplus::Pen*pen;
  Gdiplus::PointF*points;
  int len;
 }s;	// Cache für Kurvendaten
 enum action{
  NONE,ADD1,SHIFT1,FULL_NEW
 };
 void makePoly(action);	// berechnet Kurve sowie Minima und Maxima
public:
 Range rangeX,rangeY;		// tatsächlicher Definitions- und Wertebereich der aktuellen Daten
 Plot(XY*_parent,PLOT&);
 ~Plot()			{done();}
 void operator=(PLOT&pl)	{done();*(PLOT*)this=pl;init();}
 void onSize(Gdiplus::Graphics&g);
 void onPaint(Gdiplus::Graphics&g);
 void putdata(FLEXDATA&);
};

class XY{
 XY(HWND);
 ~XY();
 HWND wnd;
 HWND hPlotLegend,hScaleLegend,hCursorLegend;	// ownerdrawn ListView with checkmarks
 HWND hMiniature;		// full-extent plot without scales
 Rect rcPlot;
 std::vector<Scale*> xscales;	// typisch 1
 std::vector<Scale*> yscales;	// typisch 1-2
 std::vector<int> hdivs;
 std::vector<Plot*> plots;
 void onSize(int,int);
 void onPaint(Gdiplus::Graphics&g);
 LRESULT wndproc(UINT,WPARAM,LPARAM);
 static LRESULT CALLBACK wndproc(HWND,UINT,WPARAM,LPARAM);
 ULONG_PTR gdiplusToken;
 enum{
  PLOTDATA=1,	// Datenänderung (Auswirkung auf Skalen)
  PLOTATTR=2,	// Plotfarbe o.ä.
  SCALEEXPAND=4,// (intern) Sofortige Skalenänderung
  SCALESHRINK=8,// (intern) Verzögerte Skalenänderung
  PLOTS=16,	// Anzahl der Plots
  SCALES=32,	// Anzahl der Skalen u.ä.
 };
 void beginChange(BYTE what);
 void endChange(BYTE what);
 void shrinkScales();
 void repositionAll();
 bool timer_running;
public:
 bool needReposition;
 static BOOL init();
 Scale*getXScale(char&index);
 Scale*getYScale(char&index);
 Gdiplus::Color getPlotColor(char&index);
};
Detected encoding: UTF-80