Kreis aus Kontrollpunkten berechnen



  • Original erstellt von KXII:
    @kreisforscher
    EIN KREIS KANN AUCH EIN 3D-GEBILDE SEIN, FEDDISCH!!!:-D

    Gerade Darum Sind ja Auch 8 Punkte Notwendig! Du Hast wohl Meine Ausführungen nicht Gelesen! :o



  • ich würde sagen ein horizont hat "(1+1/x)^x für x->inf" dimensionen. kein bischen mehr und kein bischen weniger, alles andere würde zu fehler im raumzeitkontinuum führen! 😉

    @kreisforscher

    danke für den 100%igen beweis das du es dir nicht vorstellen kannst.

    [ Dieser Beitrag wurde am 21.06.2003 um 18:11 Uhr von KXII editiert. ]



  • kreisforscher hat wirklich recht 😮
    ich habs grad mal durchgerechnet 😮 😮 😮
    ES PASST!!! 😮 😮 😮 😡



  • 😮 😮
    😮 😮
    😮 😮
    😮 😮



  • KXII hat wirklich recht! Ein Horizont hat (1+1/x)^x für x->inf Dimensionen!! 😮 😮
    Ich hab's g'rad' mal durchgerechnet...
    ES PASST!!! 😮 😮 😡 😮 😮



  • NEIN!!! 😡 😡 😡



  • Original erstellt von <geraldo>:
    NEIN!!! 😡 😡 😡

    DOCH!!!! 😡 😡 😡 😡



  • Alle Punkte wirken auf den optimalen kreis, mit mehr punkten kann dieser noch feiner vorhergesagt werden, der Rechenaufwand ist mit irregulären Matritzen- Fehlern dann recht haarig.

    Das ganze basiert auch auf die Vorhersage eines Kreises wenn n aneinandergesetzte Punkte die Abstarhlrichtung vorgeben. Z.b erzeugt ein Sensor
    eine Punktewolke mit Ausreißern, es ist nun sehr schwer die Ausreißer auf der nicht genau bestimmten Kreisbahn zu lokalisieren, man kann dann die Streuung der letzten Steigung über statistisch Funktionen finden Sigma-Rauschen.

    Oftmals werden auch synthetisch so viele Modelkreise über die Punkte Wolke gelegt bis einer am besten passt..

    Alle Lösungen sind immer nicht hinreichend zufriedenstellend.

    Erste kunde: Die Kreisbahn

    //teilt einen gedachten kreis(Radius) in seqmente und erzeugt eine 
    //Position für jedes seqment, kreispunktbahn 
    void Circle::Filter(CRect rc,int DotCnt,double Radius)
    {
    	#define  FC (2.0f*PI/(double)SEGMENTS)
    	CPoint ptc(rc.CenterPoint());
    	double r(rc.Width()/2);
    	for(register short nr=0; nr<SEGMENTS; nr++)//calc dotring
    	{
    		int x = ptc.x + cos(FC*nr) * r;
    		int y = ptc.y + sin(FC*nr) * r;
    	}
    }
    

    Zweite Kunde: Bresenhalm Kreis !

    oid CGdiObj::Circle(CDC *pDC, WORD x0, WORD y0, WORD radius)
    {//breshalm :-) 
       short f = 1 - radius;
       WORD ddFx = 0,ddFy = -2 * radius;
       WORD x = 0, y = radius;
    
       while(x < y) 
       {
         if(f >= 0) 
           y--, ddFy+=2, f+=ddFy;
    
         x++, ddFx+=2, f+=ddFx+1;
    
         pDC->SetPixel(x0 + x, y0 + y,RGB(0,255,0));
         pDC->SetPixel(x0 - x, y0 + y,RGB(0,255,0));
         pDC->SetPixel(x0 + x, y0 - y,RGB(0,255,0));
         pDC->SetPixel(x0 - x, y0 - y,RGB(0,255,0));
         pDC->SetPixel(x0 + y, y0 + x,RGB(0,255,0));
         pDC->SetPixel(x0 - y, y0 + x,RGB(0,255,0));
         pDC->SetPixel(x0 + y, y0 - x,RGB(0,255,0));
         pDC->SetPixel(x0 - y, y0 - x,RGB(0,255,0));
       }
    }
    

    Dritte Kunde Kreis aus drei punkten

    bool Circle::Calc(double ScaleX, double ScaleY,double &PosX, double &PosY, double &Rad)
    {
    	// Die Unbekannten: X, Y und Radius mit Naeherungswerten
    	double X=0,Y=0,R=1;
    	unsigned int pointCnt = m_Points.size();
    	for(unsigned int iteration=0; iteration < pointCnt; iteration++)
    	{
    	   GdiMatrix A(pointCnt, 3);
    	   GdiMatrix b(pointCnt, 1);
    
    		for(unsigned int i=0; i<pointCnt; i++)
    		{
    			GdiPoint &p = m_Points[i];
    
    			p.x *= ScaleX;
    			p.y *= ScaleY;
    
    			// X
    			X+=    DX; double px=GdiPoint(X,Y).Cross(p)-R;
    			X-=2.0*DX; double mx=GdiPoint(X,Y).Cross(p)-R;
    			X+=    DX;
    			// Y
    			Y+=    DX; double py=GdiPoint(X,Y).Cross(p)-R;
    			Y-=2.0*DX; double my=GdiPoint(X,Y).Cross(p)-R;
    			Y+=    DX;
    
    			A.SetElement(i,0,(px-mx)/(2.0*DX));
    			A.SetElement(i,1,(py-my)/(2.0*DX));
    			A.SetElement(i,2,-1);
    
    			double val = GdiPoint(X,Y).Cross(p)-R;
    			b.SetElement(i,0,-val);
    		}
    
    		GdiMatrix tmpA = A.GetTransposed()*A;
    		GdiMatrix tmpB = A.GetTransposed()*b;
    
    		GdiMatrix dx = tmpA.GetInverted() * tmpB;
    
    		X = X+dx.GetElement(0,0);
    		Y = Y+dx.GetElement(1,0);
    		R = R+dx.GetElement(2,0); 
    	} 
    
    	PosX = X, PosY = Y , Rad = R;
    
        return true;	
    }
    

    Vierte Kunde: Matrix Interpolation mit irregulärer Matrix (Kreis aus drei punkten Zweite Version)

    bool Circle::Info(GdiPoint a,GdiPoint b,GdiPoint c,int &PosX, int &PosY, int &Rad)
    {
    	#define COLS 4
        #define ROWS 3
    
    	double *pM,*pMat = new double[COLS*ROWS];
    	if(!(pM=pMat))
    	 return false;
    
    	pM[0] = 1,pM[1] = -2*a.x,
    	pM[2] = -2*a.y,
    	pM[3] = -a.x*a.x-a.y*a.y;
    	pM+=COLS;
    
    	pM[0] = 1,pM[1] = -2*b.x,
    	pM[2] = -2*b.y,
    	pM[3] = -b.x*b.x-b.y*b.y;
    	pM+=COLS;
    
    	pM[0] = 1,pM[1] = -2*c.x,
    	pM[2] = -2*c.y,
    	pM[3] = -c.x*c.x-c.y*c.y;
    	pM+=COLS;
    
    	for(register int j = 0; j < ROWS; j++)
    	{   // Diagonalenfeld normalisieren
    		register double q = pMat[j * COLS + j];
    
    		if(q == 0)//Gewährleisten, daß keine 0 in der Diagonale steht
    		  for(register int i = j + 1; i < ROWS; i++)
    		   if(pMat[i * COLS + j] != 0)// Suche Reihe mit Feld <> 0 und addiere dazu
    		   {
    			  for(register int k = 0 ; k < COLS; k++)
    				pMat[j * COLS + k] += pMat[i * COLS + k];
    
    			  q = pMat[j * COLS + j];
    			  break;
    		   }
    
    		if(q != 0)// Diagonalen auf 1 bringen
    		  for(register int k = 0; k < COLS; k++)
    			pMat[j * COLS + k] = pMat[j * COLS + k] / q;
    
    		for(register int i = 0 ; i < ROWS; i++)
    		 if(i != j )// Spalten außerhalb der Diagonalen auf 0 bringen
    		 {
    			q = pMat[i * COLS + j];
    
    			for(register int k = 0; k < COLS; k++)
    			  pMat[i * COLS + k] -=  q * pMat[j * COLS + k];    
    		  } 
    	}
    
    	bool stat(pMat[0] != 1 || pMat[5] != 1 || pMat[10] != 1);
    
    	if (stat)//irrationale matrix
    	{
    		PosX = pMat[7];
    		PosY = pMat[11];
    		Rad = (sqrt(PosX*PosX + PosY*PosY - pMat[3]));
    	}
    
    	delete pMat;
    
    	return stat;
    }
    

    Fünfte Kunde: Die spline Line
    bringt einen auch leicht in die klapse.

    #ifndef _SPLINE_H
    #define _SPLINE_H
    
    #define DIV_FACTOR 4 //adjust this factor to adjust the curve smoothness
    class Curve
    {
    public:
    	float  Ax,Ay;
    	float  Bx,By;
    	float  Cx,Cy;
    	int    Ndiv;
    
    	Curve(float ax,float ay,float bx,float by,float cx,float cy,int ndiv) 
    	{
    		Ax = ax;
    		Ay = ay;
    		Bx = bx;
    		By = by;
    		Cx = cx;
    		Cy = cy;
    		Ndiv = ndiv;
    	}
    
    	Curve(float ax,float ay,float bx,float by,float cx,float cy)
    	{
    		Ax = ax; 
    		Ay = ay;
    		Bx = bx; 
    		By = by;
    		Cx = cx; 
    		Cy = cy;
    		Ndiv = (int)(max(abs((int)Ax),abs((int)Ay))/DIV_FACTOR);
    	}
    	Curve() 
    	{	
    	};
    
    	void PutCurve(float ax,float ay,float bx,float by,float cx,float cy) 
    	{
    		Ax = ax;
    		Ay = ay;
    		Bx = bx; 
    		By = by;
    		Cx = cx; 
    		Cy = cy;
    		Ndiv = (int)(max(abs((int)Ax),abs((int)Ay))/DIV_FACTOR);
    	}
    
    	void draw(HDC hdc,float x,float y) 
    	{
    		int OrigX,OrigY,NewX,NewY;
    		float  t,f,g,h;
    		if (Ndiv==0)
    			Ndiv=1;
    
    		OrigX = (int)x; 
    		OrigY= (int)y;
    		for(int i=1; i<=Ndiv ; i++)
    		{
    			t = 1.0f / (float)Ndiv * (float)i;
    			f = t*t*(3.0f-2.0f*t);
    			g = t*(t-1.0f)*(t-1.0f);
    			h = t*t*(t-1.0f);
    			NewX = (int)(x + Ax*f + Bx*g + Cx*h);
    			NewY = (int)(y + Ay*f + By*g + Cy*h);
    			MoveToEx(hdc, OrigX, OrigY, NULL);
    			LineTo(hdc, NewX, NewY);
    			OrigX = NewX;  
    			OrigY=NewY;
    		}
    	}
    	int GetCount()
    	{
    		if (Ndiv==0)
    			Ndiv=1;
    		int PointCount = 1;
    
    		for(int i=1; i<=Ndiv ; i++)
    		{
    			PointCount++;
    		}
    		return PointCount;
    	}
    	void GetCurve(float x,float y, POINT points[], int& PointCount)
    	{
    		int X,Y;
    		float  t,f,g,h;
    		if (Ndiv==0)
    			Ndiv=1;
    
    		X = (int)x; 
    		Y= (int)y;
    		points[PointCount].x = X;
    		points[PointCount].y = Y;
    		PointCount++;
    
    		for(int i=1; i<=Ndiv ; i++)
    		{
    			t = 1.0f / (float)Ndiv * (float)i;
    			f = t*t*(3.0f-2.0f*t);
    			g = t*(t-1.0f)*(t-1.0f);
    			h = t*t*(t-1.0f);
    			X = (int)(x + Ax*f + Bx*g + Cx*h);
    			Y = (int)(y + Ay*f + By*g + Cy*h);
    			points[PointCount].x = X;
    			points[PointCount].y = Y;
    			PointCount++;
    		}
    	}
    
    };
    
    class Spline 
    {
    public:
    	float* Px;
    	float* Py;
    	float* Ax;
    	float* Ay;
    	float* Bx;
    	float* By;
    	float* Cx;
    	float* Cy;
    	float*  k;
    	float*  Mat[3];
    
    	int  NP;
    
    	// constructor
    	Spline(POINT pt[], int np)
    	{
    		NP = np;
    		Px = new float[NP];
    		Py = new float[NP];
    		Ax = new float[NP];
    		Ay = new float[NP];
    		Bx = new float[NP];
    		By = new float[NP];
    		Cx = new float[NP];
    		Cy = new float[NP];
    		k = new float[NP];
    		Mat[0] = new float[NP];
    		Mat[1] = new float[NP];
    		Mat[2] = new float[NP];
    
    		for(int i=0;i<NP ;i++) 
    		{
    			Px[i] = (float)pt[i].x;  
    			Py[i] = (float)pt[i].y;
    		}
    	}
    
    	Spline(float px[] , float py[] , int np) 
    	{
    		NP = np;
    		Px = new float[NP];
    		Py = new float[NP];
    		Ax = new float[NP];
    		Ay = new float[NP];
    		Bx = new float[NP];
    		By = new float[NP];
    		Cx = new float[NP];
    		Cy = new float[NP];
    		k = new float[NP];
    		Mat[0] = new float[NP];
    		Mat[1] = new float[NP];
    		Mat[2] = new float[NP];
    
    		for(int i=0;i<NP ;i++) 
    		{
    			Px[i] = px[i];  
    			Py[i] = py[i];
    		}
    	}
    
    	~Spline()
    	{
    		delete[] Px;
    		delete[] Py;
    		delete[] Ax;
    		delete[] Ay;
    		delete[] Bx;
    		delete[] By;
    		delete[] Cx;
    		delete[] Cy;
    		delete[] k;
    		delete[] Mat[0];
    		delete[] Mat[1];
    		delete[] Mat[2];
    	}
    
    	void Generate() 
    	{
    		float AMag , AMagOld;
        	// vector A
    		for(int i= 0 ; i<=NP-2 ; i++ ) 
    		{
    			Ax[i] = Px[i+1] - Px[i];
    			Ay[i] = Py[i+1] - Py[i];
    		}
    		// k
    		AMagOld = (float)sqrt(Ax[0]*Ax[0] + Ay[0]*Ay[0]);
    		for(register int i=0 ; i<=NP-3 ; i++) 
    		{
    			AMag = (float)sqrt(Ax[i+1]*Ax[i+1] + Ay[i+1]*Ay[i+1]);
    			k[i] = AMagOld / AMag;
    			AMagOld = AMag;
    		}
    		k[NP-2] = 1.0f;
    
    		// Matrix
    		for(register int i=1; i<=NP-2;i++) 
    		{
    			Mat[0][i] = 1.0f;
    			Mat[1][i] = 2.0f*k[i-1]*(1.0f + k[i-1]);
    			Mat[2][i] = k[i-1]*k[i-1]*k[i];
    		}
    		Mat[1][0] = 2.0f;
    		Mat[2][0] = k[0];
    		Mat[0][NP-1] = 1.0f;
    		Mat[1][NP-1] = 2.0f*k[NP-2];
    
    		// 
    		for(register int i=1; i<=NP-2;i++) 
    		{
    			Bx[i] = 3.0f*(Ax[i-1] + k[i-1]*k[i-1]*Ax[i]);
    			By[i] = 3.0f*(Ay[i-1] + k[i-1]*k[i-1]*Ay[i]);
    		}
    		Bx[0] = 3.0f*Ax[0];
    		By[0] = 3.0f*Ay[0];
    		Bx[NP-1] = 3.0f*Ax[NP-2];
    		By[NP-1] = 3.0f*Ay[NP-2];
    
    		//
    		MatrixSolve(Bx);
    		MatrixSolve(By);
    
    		for(register int i=0 ; i<=NP-2 ; i++ ) 
    		{
    			Cx[i] = k[i]*Bx[i+1];
    			Cy[i] = k[i]*By[i+1];
    		}
    	}
    
    	void MatrixSolve(float B[]) 
    	{
    		float* Work = new float[NP];
    		float* WorkB = new float[NP];
    		for(int i=0;i<=NP-1;i++) 
    		{
    			Work[i] = B[i] / Mat[1][i];
    			WorkB[i] = Work[i];
    		}
    
    		for(int j=0 ; j<10 ; j++) 
    		{ ///  need convergence judge
    			Work[0] = (B[0] - Mat[2][0]*WorkB[1])/Mat[1][0];
    			for(int i=1; i<NP-1 ; i++ ) 
    			{
    				Work[i] = (B[i]-Mat[0][i]*WorkB[i-1]-Mat[2][i]*WorkB[i+1])
    							/Mat[1][i];
    			}
    			Work[NP-1] = (B[NP-1] - Mat[0][NP-1]*WorkB[NP-2])/Mat[1][NP-1];
    
    			for(register int i=0 ; i<=NP-1 ; i++ ) 
    			{
    				WorkB[i] = Work[i];
    			}
    		}
    		for(register int i=0 ; i<=NP-1 ; i++ ) 
    		{
    			B[i] = Work[i];
    		}
    		delete[] Work;
    		delete[] WorkB;
    	}
    
    	void draw(HDC hdc) 
    	{
    		Curve c;
    		for(int i=0; i<NP-1 ; i++) 
    		{
    			c.PutCurve(Ax[i],Ay[i],Bx[i],By[i],Cx[i],Cy[i]);
    			c.draw(hdc,Px[i],Py[i]);
    		}
    
    	}
    	int GetCurveCount()
    	{
    		Curve c;
    		int count = 0;
    		for(int i=0; i<NP-1 ; i++) 
    		{
    			c.PutCurve(Ax[i],Ay[i],Bx[i],By[i],Cx[i],Cy[i]);
    			count += c.GetCount();
    		}
    		return count;
    	}
    	void GetCurve(POINT points[], int& PointCount)
    	{
    		Curve c;
    		for(int i=0; i<NP-1 ; i++) 
    		{
    			c.PutCurve(Ax[i],Ay[i],Bx[i],By[i],Cx[i],Cy[i]);
    			c.GetCurve(Px[i],Py[i], points, PointCount);
    		}
    	}
      //////////// closed cubic spline ////////////////////
    	void GenClosed() 
    	{
    		float AMag , AMagOld , AMag0;
            // vector A
    		for(int i= 0 ; i<=NP-2 ; i++ ) 
    		{
    			Ax[i] = Px[i+1] - Px[i];
    			Ay[i] = Py[i+1] - Py[i];
    		}
    		Ax[NP-1] = Px[0] - Px[NP-1];
    		Ay[NP-1] = Py[0] - Py[NP-1];
    
    		// k
    		AMag0 = AMagOld = (float)sqrt(Ax[0]*Ax[0] + Ay[0]*Ay[0]);
    		for(register int i=0 ; i<=NP-2 ; i++) 
    		{
    			AMag = (float)sqrt(Ax[i+1]*Ax[i+1] + Ay[i+1]*Ay[i+1]);
    			k[i] = AMagOld / AMag;
    			AMagOld = AMag;
    		}
    		k[NP-1]=AMagOld/AMag0; 
    
    		// Matrix
    		for(register int i=1; i<=NP-1;i++) 
    		{
    			Mat[0][i] = 1.0f;
    			Mat[1][1] = 2.0f*k[i-1]*(1.0f + k[i-1]);
    			Mat[2][i] = k[i-1]*k[i-1]*k[i];
    		}
    		Mat[0][0] = 1.0f;
    		Mat[1][0] = 2.0f*k[NP-1]*(1.0f + k[NP-1]);
    		Mat[2][0] = k[NP-1]*k[NP-1]*k[0];
    
    		// 
    		for(register int i=1; i<=NP-1;i++) 
    		{
    			Bx[i] = 3.0f*(Ax[i-1] + k[i-1]*k[i-1]*Ax[i]);
    			By[i] = 3.0f*(Ay[i-1] + k[i-1]*k[i-1]*Ay[i]);
    		}
    		Bx[0] = 3.0f*(Ax[NP-1] + k[NP-1]*k[NP-1]*Ax[0]);
    		By[0] = 3.0f*(Ay[NP-1] + k[NP-1]*k[NP-1]*Ay[0]);
    
    		//
    		MatrixSolveEX(Bx);
    		MatrixSolveEX(By);
    
    		for(register int i=0 ; i<=NP-2 ; i++ ) 
    		{
    			Cx[i] = k[i]*Bx[i+1];
    			Cy[i] = k[i]*By[i+1];
    		}
    		Cx[NP-1] = k[NP-1]*Bx[0];
    		Cy[NP-1] = k[NP-1]*By[0];
    	}
    
      ///// tridiagonal matrix + elements of [0][0], [N-1][N-1] //// 
    	void MatrixSolveEX(float B[]) 
    	{
    		float* Work = new float[NP];
    		float* WorkB = new float[NP];
    
    		for(int i=0;i<=NP-1;i++) 
    		{
    			Work[i] = B[i] / Mat[1][i];
    			WorkB[i] = Work[i];
    		}
    
    		for(int j=0 ; j<10 ; j++) 
    		{  // need judge of convergence
    			Work[0] = (B[0]-Mat[0][0]*WorkB[NP-1]-Mat[2][0]*WorkB[1])
    					/Mat[1][0];
    			for(int i=1; i<NP-1 ; i++ ) 
    			{
    				Work[i] = (B[i]-Mat[0][i]*WorkB[i-1]-Mat[2][i]*WorkB[i+1])
    							/Mat[1][i];
    			}
    			Work[NP-1] = (B[NP-1]-Mat[0][NP-1]*WorkB[NP-2]-Mat[2][NP-1]*WorkB[0])
    							/Mat[1][NP-1];
    
    			for(register int i=0 ; i<=NP-1 ; i++ ) 
    			{
    				WorkB[i] = Work[i];
    			}
    		}
    
    		for(register int i=0 ; i<=NP-1 ; i++ ) 
    		{
    			B[i] = Work[i];
    		}
    
    		delete[] Work;
    		delete[] WorkB;
    	}
    
    	void drawClosed(HDC hdc) 
    	{
    		Curve c;
    		for(int i=0; i<NP ; i++) 
    		{
    			c.PutCurve(Ax[i],Ay[i],Bx[i],By[i],Cx[i],Cy[i]);
    			c.draw(hdc ,Px[i],Py[i]);
    		}
    	}
    };
    
    #endif
    

    Hier noch der benötigte Matrix Stuff:

    Header für Matrix

    class GdiMatrix
    {
    public:
    
    public:
    	friend class	MatrixHelper ;						// used for operator[][]
    	// construction and destruction
    					GdiMatrix() ;							// default constructor
    					GdiMatrix(const GdiMatrix &other) ;		// copy constructor
    					GdiMatrix(int nCols, int nRows) ;		// constructs an empty matrix of this size
    					GdiMatrix(int size, bool set_diagonal = true) ;	// creates a square matrix
    //					GdiMatrix(VARIANT& var) ;				// from a SAFEARRAY variant
    	virtual			~GdiMatrix();							// destructor
    
    	// matrix mathematical operations
    	GdiMatrix&		operator=(const GdiMatrix &other) ;
    	GdiMatrix			operator+(const GdiMatrix &other) const ;
    	GdiMatrix			operator-(const GdiMatrix &other) const ;
    	GdiMatrix			operator*(const GdiMatrix &other) const ;
    	void			operator+=(const GdiMatrix &other) ;
    	void			operator-=(const GdiMatrix &other) ;
    	void			operator*=(const GdiMatrix &other) ;
    	void			operator*=(double value) ;
    	friend GdiMatrix	operator*(const GdiMatrix &other, double value) ;
    	bool			operator==(const GdiMatrix &other) const ;
    	const MatrixHelper	operator[](int nCol) const ;			// reading version
    	MatrixHelper	operator[](int nCol) ;					// writing version
    
    	// element access
    	bool			SetElement(int nCol, int nRow, double value) ;
    #ifdef _DEBUG
    	double			GetElement(int nCol, int nRow) const ;
    #else
    	inline double	GetElement(int nCol, int nRow) const { return m_pData[nCol + nRow * m_NumColumns] ; } ;
    #endif
    	inline int		GetNumColumns() const { return m_NumColumns ; } ;
    	inline int		GetNumRows() const { return m_NumRows ; } ;
    	double			SumColumn(int col) const ;
    	double			SumRow(int row) const ;
    	double			SumColumnSquared(int col) const ;
    	double			SumRowSquared(int row) const ;
    	double			GetRowMin(int row) const ;
    	double			GetRowMax(int row) const ;
    	double			GetColumnMin(int col) const ;
    	double			GetColumnMax(int col) const ;
    	// matrix transposition
    	GdiMatrix			GetTransposed() const ;
    	void			Transpose() ;
    	// matrix inversion
    	GdiMatrix			GetInverted() const ;
    	void			Invert() ;
    	// covariant (A' * A)
    	GdiMatrix			Covariant() const ;
    	// normalisation
    	GdiMatrix			GetNormalised(double min, double max) const ;
    	void			Normalise(double min, double max) ;
    	// ranges functions
    	void			GetNumericRange(double &min, double &max) const ;
    	// matrix concatenation
    	GdiMatrix			GetConcatinatedColumns(const GdiMatrix& other) const ;
    	void			ConcatinateColumns(const GdiMatrix &other) ;
    	GdiMatrix			GetConcatinatedRows(const GdiMatrix& other) const ;
    	void			ConcatinateRows(const GdiMatrix &other) ;
    	// adds an new row / column to the matrix
    	void			AddColumn(const double *pData) ;
    	void			AddRow(const double *pData) ;
    	// sub matrix extraction, setting
    	GdiMatrix			ExtractSubMatrix(int col_start, int row_start, int col_size, int row_size) const ;
    	void			SetSubMatrix(int col_start, int row_start, const GdiMatrix &other) ;
    	GdiMatrix			ExtractDiagonal() const ;
    	// squaring the matrix functions
    	GdiMatrix			GetSquareMatrix() const ;
    	void			MakeSquare() ;
    	// export functions/import
    	void			CopyToClipboard() const ;
    
    private:
    	// internal variables
    	int				m_NumColumns ;			// number of columns in matrix
    	int				m_NumRows ;				// number of rows in matrix
    	double*			m_pData ;				// pointer to data, may be shared among objects
    #ifdef _DEBUG
    	// variables used in debug for obejct counting
    	static int		m_NextObjectNumber ;
    	int				m_ObjectNumber ;
    #endif
    private:
    	// private internal functions
    	double*			AllocateMemory(int nCols, int nROws) ;
    	// reference counting functions
    	void			IncrementReferenceCount() ;	// increments the m_pData reference count
    	void			DecrementReferenceCount() ;	// decrements the m_pData reference count
    	void			DecrementAndRelease() ;		// decrements the count and releases the memory if required
    	int				GetReferenceCount() const ;	// returns the m_pData's reference count
    	// helper functions
    	CString			GetRowAsText(int row) const ;
    	static CString	ReadLine(CFile &file) ;		// reads a \r\n delimited line of text from a file
    	static int		GetStringToken(CString source, CString &destination, int start, char ch) ;
    };
    
    // this class is used to help the operator[][] on a matrix object work correctly
    // it only provides the operator[]
    class MatrixHelper
    {
    public:
    	friend class	GdiMatrix ;
    protected:
    	// protected constructor so only friend class can construct
    	// a MatrixHelper object
    					MatrixHelper(GdiMatrix* pMatrix, int col) : m_pMatrix(pMatrix), m_pMatrixConst(NULL)
    						{
    						m_Col = col ;
    						} ;
    					MatrixHelper(const GdiMatrix* const pMatrix, int col) : m_pMatrixConst(pMatrix), m_pMatrix(NULL)
    						{
    						m_Col = col ;
    						} ;
    					MatrixHelper(MatrixHelper& other) : m_pMatrix(other.m_pMatrix), m_pMatrixConst(other.m_pMatrixConst)
    						{
    						m_Col = other.m_Col ;
    						} ;
    public:
    					~MatrixHelper()
    						{
    						} ;
    	double			operator[](int row) const
    						{
    						ASSERT(row >= 0) ;									// array bounds error
    						ASSERT(row < m_pMatrixConst->m_NumRows) ;				// array bounds error
    						return m_pMatrixConst->m_pData[row * m_pMatrixConst->m_NumColumns + m_Col] ;
    						} ;
    	double&			operator[](int row)
    						{
    						// first check the reference count on our data object to see whether we need to create a copy
    						if (m_pMatrix->GetReferenceCount() > 1)
    							{
    							// we need to make a copy
    							double	*pData = m_pMatrix->m_pData ;			// take a copy of the pointer
    							m_pMatrix->DecrementReferenceCount() ;			// decrement the current reference count
    							m_pMatrix->m_pData = m_pMatrix->AllocateMemory(m_pMatrix->m_NumColumns, m_pMatrix->m_NumRows) ;
    							memcpy(m_pMatrix->m_pData, pData, sizeof(double) * m_pMatrix->m_NumColumns * m_pMatrix->m_NumRows) ;
    							m_pMatrix->IncrementReferenceCount() ;			// increment the new data's reference count
    							}
    						ASSERT(row >= 0) ;									// array bounds error
    						ASSERT(row < m_pMatrix->m_NumRows) ;					// array bounds error
    						ASSERT(m_pMatrix->m_pData) ;
    						return m_pMatrix->m_pData[m_Col + row * m_pMatrix->m_NumColumns] ;
    						} ;
    private:
    
    	GdiMatrix*		m_pMatrix ;
    	const GdiMatrix*	m_pMatrixConst ;
    	int				m_Col ;						// column index for operator[][]
    } ;
    

    Matrix Code

    #include "stdafx.h"
    #include "Matrix.h"
    
    GdiMatrix::GdiMatrix()
    {
    	// default constructor, create a 1 * 1 array
    	m_NumColumns = 1 ;
    	m_NumRows = 1 ;
    	m_pData = NULL ;
    	m_pData = AllocateMemory(m_NumColumns, m_NumRows) ;
    	IncrementReferenceCount() ;			// count the reference to this memory
    }
    
    GdiMatrix::GdiMatrix(const GdiMatrix &other)
    {
    	// copy constructor
    	m_pData = NULL ;
    	// use the other objects data pointer
    	m_NumColumns = other.m_NumColumns ;
    	m_NumRows = other.m_NumRows ;
    	m_pData = other.m_pData ;				// copy the pointer
    	IncrementReferenceCount() ;				// this thread can get the mutex multiple times without blocking
    }
    
    GdiMatrix::GdiMatrix(int nCols, int nRows)
    {
    	// size constructor
    	ASSERT(nCols > 0) ;					// matrix size error
    	ASSERT(nRows > 0) ;					// matrix size error
    	m_pData = NULL ;
    	m_NumColumns = nCols ;
    	m_NumRows = nRows ;
    	m_pData = AllocateMemory(m_NumColumns, m_NumRows) ;
    	IncrementReferenceCount() ;				// count the reference to this memory
    }
    
    GdiMatrix::GdiMatrix(int size, bool set_diagonal)
    {
    	// size constructor
    	ASSERT(size > 0) ;						// matrix size error
    	m_pData = NULL ;
    	m_NumColumns = size ;
    	m_NumRows = size ;
    	m_pData = AllocateMemory(m_NumColumns, m_NumRows) ;
    	IncrementReferenceCount() ;				// count the reference to this memory
    	// set the dialognal if required
    	if (set_diagonal)
    		{
    		for (int i = 0 ; i < size ; ++i)
    			SetElement(i, i, 1.0) ;
    		}
    }
    
    GdiMatrix::~GdiMatrix()
    {
    #ifdef _DEBUG
    	TRACE("Destroying GdiMatrix object %1d\n", m_ObjectNumber) ;
    #endif
    	DecrementAndRelease() ;			// free's m_pData if no other references
    }
    
    double* GdiMatrix::AllocateMemory(int nCols, int nRows)
    {
    	ASSERT(nCols > 0) ;							// size error
    	ASSERT(nRows > 0) ;							// size error
    	// allocates heap memory for an array
    	double	*pData = NULL ;
    
    	pData = new double[nCols * nRows + 1] ;			// all in one allocation (+1 for reference count)
    	ASSERT(pData != NULL) ;					// allocation error
    	ASSERT(FALSE == IsBadReadPtr(pData, sizeof(double) * (nCols * nRows + 1))) ;
    	// empty the memory
    	memset(pData, 0, sizeof(double) * (nCols * nRows + 1)) ;		// starts with a 0 reference count
    	return pData ;
    }
    
    GdiMatrix& GdiMatrix::operator=(const GdiMatrix &other)
    {
    	if (&other == this)
    		return *this ;
    	// this does the same job as a copy constructor except we have to de-allocate any
    	// memory we may have already allocated
    	DecrementAndRelease() ;			// free's m_pData if no other references
    	// now copy the other matrix into ourselves
    	// use the other objects data pointer
    	m_NumColumns = other.m_NumColumns ;
    	m_NumRows = other.m_NumRows ;
    	m_pData = other.m_pData ;				// copy the pointer
    	IncrementReferenceCount() ;				// this thread can get the mutex multiple times without blocking
    	// finally return a reference to ourselves
    	return *this ;
    }
    
    bool GdiMatrix::operator==(const GdiMatrix &other) const
    {
    	// only return true if the matrices are exactly the same
    	if (&other == this)
    		return true ;		// comparing to ourselves
    	if (m_pData == other.m_pData)
    		return true ;		// both pointing to same data, must be same
    	if (m_NumColumns != other.m_NumColumns || m_NumRows != other.m_NumRows)
    		return false ;		// different dimensions
    	if (memcmp(m_pData, other.m_pData, sizeof(double) * m_NumColumns * m_NumRows) == 0)
    		return true ;		// buffers are the same
    	return false ;			// must be different
    }
    
    GdiMatrix GdiMatrix::operator+(const GdiMatrix &other) const
    {
    	// first check for a valid addition operation
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Invalid operation" ;
    	if (m_NumRows != other.m_NumRows)
    		throw "Invalid operation" ;
    	// now that we know that the operation is possible
    	ASSERT(FALSE == IsBadReadPtr(other.m_pData, sizeof(double) * other.m_NumColumns * other.m_NumRows)) ;
    	// construct the object we are going to return
    	GdiMatrix		result(*this) ;		// copy ourselves
    	// now add in the other matrix
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			result.SetElement(i, j, result.GetElement(i, j) + other.GetElement(i, j)) ;
    		}
    	return result ;
    }
    
    GdiMatrix GdiMatrix::operator-(const GdiMatrix &other) const
    {
    	// first check for a valid subtraction operation
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Invalid operation" ;
    	if (m_NumRows != other.m_NumRows)
    		throw "Invalid operation" ;
    	// now that we know that the operation is possible
    	ASSERT(FALSE == IsBadReadPtr(other.m_pData, sizeof(double) * other.m_NumColumns * other.m_NumRows)) ;
    	// construct the object we are going to return
    	GdiMatrix		result(*this) ;		// copy ourselves
    	// now subtract the other matrix
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			result.SetElement(i, j, result.GetElement(i, j) - other.GetElement(i, j)) ;
    		}
    	return result ;
    }
    
    GdiMatrix GdiMatrix::operator*(const GdiMatrix &other) const
    {
    	// first check for a valid multiplication operation
    	if (m_NumRows != other.m_NumColumns)
    		throw "Matrices do not have common size" ;
    	// now that we know that the operation is possible
    	ASSERT(FALSE == IsBadReadPtr(other.m_pData, sizeof(double) * other.m_NumColumns * other.m_NumRows)) ;
    	// construct the object we are going to return
    	GdiMatrix		result(m_NumColumns, other.m_NumRows) ;
    
    	// e.g.
    	// [A][B][C]   [G][H]     [A*G + B*I + C*K][A*H + B*J + C*L]
    	// [D][E][F] * [I][J] =   [D*G + E*I + F*K][D*H + E*J + F*L]
    	//             [K][L]
    	//
    	double	 value ;
    	for (int i = 0 ; i < result.m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < result.m_NumRows ; ++j)
    			{
    			value = 0.0 ;
    			for (int k = 0 ; k < m_NumRows ; ++k)
    				{
    				value += GetElement(i, k) * other.GetElement(k, j) ;
    				}
    			result.SetElement(i, j, value) ;
    			}
    		}
    	return result ;
    }
    
    void GdiMatrix::operator+=(const GdiMatrix &other)
    {
    	// first check for a valid addition operation
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Invalid operation" ;
    	if (m_NumRows != other.m_NumRows)
    		throw "Invalid operation" ;
    	// now that we know that the operation is possible
    	ASSERT(FALSE == IsBadReadPtr(other.m_pData, sizeof(double) * other.m_NumColumns * other.m_NumRows)) ;
    	// now add in the other matrix
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			SetElement(i, j, GetElement(i, j) + other.GetElement(i, j)) ;
    		}
    }
    
    void GdiMatrix::operator-=(const GdiMatrix &other)
    {
    	// first check for a valid subtraction operation
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Invalid operation" ;
    	if (m_NumRows != other.m_NumRows)
    		throw "Invalid operation" ;
    	// now that we know that the operation is possible
    	ASSERT(FALSE == IsBadReadPtr(other.m_pData, sizeof(double) * other.m_NumColumns * other.m_NumRows)) ;
    	// now subtract the other matrix
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			SetElement(i, j, GetElement(i, j) - other.GetElement(i, j)) ;
    		}
    }
    
    void GdiMatrix::operator*=(const GdiMatrix &other)
    {
    	// first check for a valid multiplication operation
    	if (m_NumRows != other.m_NumColumns)
    		throw "Matrices do not have common size" ;
    
    	*this = *this * other ;
    }
    
    void GdiMatrix::operator*=(double value)
    {
    	// just multiply the elements by the value
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			SetElement(i, j, GetElement(i, j) * value) ;
    			}
    		}
    }
    
    // MatrixHelper is only used for this to simulate a GdiMatrix::operator[][]
    const MatrixHelper GdiMatrix::operator[](int nCol) const
    {
    	ASSERT(nCol >= 0) ;							// array bounds error
    	ASSERT(nCol < m_NumColumns) ;				// array bounds error
    	// construc the MatrixHelper object to allow operator[][] to work
    	MatrixHelper	mh(this, nCol) ;
    	return mh ;
    }
    
    MatrixHelper GdiMatrix::operator[](int nCol)
    {
    	ASSERT(nCol >= 0) ;							// array bounds error
    	ASSERT(nCol < m_NumColumns) ;				// array bounds error
    	// construc the MatrixHelper object to allow operator[][] to work
    	MatrixHelper	mh(this, nCol) ;
    	return mh ;
    }
    
    bool GdiMatrix::SetElement(int nCol, int nRow, double value)
    {
    	// first check the reference count on our data object to see whether we need to create a copy
    	if (GetReferenceCount() > 1)
    		{
    		// we need to make a copy
    		double	*pData = m_pData ;				// take a copy of the pointer
    		DecrementReferenceCount() ;				// decrement the current reference count
    		m_pData = AllocateMemory(m_NumColumns, m_NumRows) ;
    		memcpy(m_pData, pData, sizeof(double) * m_NumColumns * m_NumRows) ;
    		IncrementReferenceCount() ;				// increment the new data's reference count
    		}
    	ASSERT(nCol >= 0) ;							// array bounds error
    	ASSERT(nCol < m_NumColumns) ;						// array bounds error
    	ASSERT(nRow >= 0) ;							// array bounds error
    	ASSERT(nRow < m_NumRows) ;						// array bounds error
    	ASSERT(m_pData) ;							// bad pointer error
    	m_pData[nCol + nRow * m_NumColumns] = value ;
    	return true ;
    }
    
    #ifdef _DEBUG
    // release version is in-line
    double GdiMatrix::GetElement(int nCol, int nRow) const
    {
    	ASSERT(nCol >= 0) ;							// array bounds error
    	ASSERT(nCol < m_NumColumns) ;						// array bounds error
    	ASSERT(nRow >= 0) ;							// array bounds error
    	ASSERT(nRow < m_NumRows) ;						// array bounds error
    	ASSERT(m_pData) ;							// bad pointer error
    	return m_pData[nCol + nRow * m_NumColumns] ;
    }
    #endif
    
    // 
    // To avoid big hits when constructing and assigning GdiMatrix objects, multiple GdiMatrix's can reference
    // the same m_pData member. Only when a matrix becomes different from the other does a new version of the array
    // get created and worked with.
    //
    void GdiMatrix::IncrementReferenceCount()
    {
    	// get a pointer to the end of the m_pData object where the reference count resides
    	int*	pReference = (int*)&m_pData[m_NumColumns * m_NumRows] ;
    	++(*pReference) ;				// increment the reference count
    	// done!
    }
    
    void GdiMatrix::DecrementReferenceCount()
    {
    	// get a pointer to the end of the m_pData object where the reference count resides
    	int*	pReference = (int*)&m_pData[m_NumColumns * m_NumRows] ;
    	--(*pReference) ;				// decrement the reference count
    	// done!
    }
    
    void GdiMatrix::DecrementAndRelease()
    {
    	// get a pointer to the end of the m_pData object where the reference count resides
    	int*	pReference = (int*)&m_pData[m_NumColumns * m_NumRows] ;
    	--(*pReference) ;				// decrement the reference count
    	if (*pReference == 0)
    		{
    		// the memory is no longer needed, release it
    		delete []m_pData ;
    		m_pData = NULL ;
    		}
    	// done!
    }
    
    int GdiMatrix::GetReferenceCount() const
    {
    	// get a pointer to the end of the m_pData object where the reference count resides
    	int*	pReference = (int*)&m_pData[m_NumColumns * m_NumRows] ;
    	return *pReference ;
    }
    
    GdiMatrix GdiMatrix::GetTransposed() const
    {
    	GdiMatrix	transposed(*this) ;		// make a copy of ourselves
    
    	transposed.Transpose() ;
    	return transposed ;
    }
    
    void GdiMatrix::Transpose()
    {
    	// first check the reference count on our data object to see whether we need to create a copy
    	GdiMatrix	mcopy(*this) ;
    	// swap the x/y values
    	int	copy = m_NumColumns ;
    	m_NumColumns = m_NumRows ;
    	m_NumRows = copy ;
    	// copy across the transposed data
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			SetElement(i, j, mcopy.GetElement(j, i)) ;
    		}
    }
    
    GdiMatrix GdiMatrix::GetInverted() const
    {
    	// matrix inversion will only work on square matrices
    	if (m_NumColumns != m_NumRows)
    		throw "GdiMatrix must be square." ;
    	// return this matrix inverted
    	GdiMatrix	copy(*this) ;
    	copy.Invert() ;
    
    	return copy ;
    }
    
    void GdiMatrix::Invert()
    {
    	// matrix inversion will only work on square matrices
    	// invert ourselves
    	if (m_NumColumns != m_NumRows)
    		throw "GdiMatrix must be square." ;
    	double	e ;
    
    	for (int k = 0 ; k < m_NumColumns ; ++k)
    		{
    		e = GetElement(k, k) ;
    		SetElement(k, k, 1.0) ;
    		if (e == 0.0)
    			break;//throw "GdiMatrix inversion error" ;
    
    		for (int j = 0 ; j < m_NumColumns ; ++j)
    			SetElement(k, j, GetElement(k, j) / e) ;
    		for (int i = 0 ; i < m_NumColumns ; ++i)
    			{
    			if (i != k)
    				{
    				e = GetElement(i, k) ;
    				SetElement(i, k, 0.0) ;
    				for (int j = 0 ; j < m_NumColumns ; ++j)
    					SetElement(i, j, GetElement(i, j) - e * GetElement(k, j)) ;
    				}
    			}
    		}
    }
    
    // A' * A
    GdiMatrix GdiMatrix::Covariant() const
    {
    	GdiMatrix	result ;
    	GdiMatrix trans(GetTransposed()) ;
    
    	result = *this * trans ;
    	return result ;
    }
    
    GdiMatrix GdiMatrix::ExtractSubMatrix(int col_start, int row_start, int col_size, int row_size) const
    {
    	ASSERT(col_start >= 0) ;						// bad start index
    	ASSERT(row_start >= 0) ;						// bad start index
    	ASSERT(col_size > 0) ;						// bad size
    	ASSERT(row_size > 0) ;						// bad size
    	// make sure the requested sub matrix is in the current matrix
    	if (col_start + col_size > m_NumColumns)
    		throw "Sub matrix is not contained in source" ;
    	if (row_start + row_size > m_NumRows)
    		throw "Sub matrix is not contained in source" ;
    
    	GdiMatrix sub(col_size, row_size) ;
    
    	for (int i = 0 ; i < col_size ; ++i)
    		{
    		for (int j = 0 ; j < row_size ; ++j)
    			{
    			sub.SetElement(i, j, GetElement(col_start + i, row_start + j)) ;
    			}
    		}
    	return sub ;
    }
    
    void GdiMatrix::SetSubMatrix(int col_start, int row_start, const GdiMatrix &other)
    {
    	ASSERT(col_start >= 0) ;						// bad start index
    	ASSERT(row_start >= 0) ;						// bad start index
    	ASSERT(col_start + other.m_NumColumns <= m_NumColumns) ;	// bad size
    	ASSERT(row_start + other.m_NumRows <= m_NumRows) ;	// bad size
    	for (int i = 0 ; i < other.m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < other.m_NumRows ; ++j)
    			{
    			SetElement(col_start + i, row_start + j, other.GetElement(i, j)) ;
    			}
    		}
    }
    
    GdiMatrix GdiMatrix::ExtractDiagonal() const
    {
    	if (m_NumColumns != m_NumRows)
    		throw "Can only extract diagonal from square matrix" ;
    	GdiMatrix	diagonal(m_NumColumns, 1) ;
    
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		diagonal.SetElement(i, 0, GetElement(i, i)) ;
    	return diagonal ;
    }
    
    GdiMatrix GdiMatrix::GetConcatinatedColumns(const GdiMatrix& other) const
    {
    	if (m_NumRows != other.m_NumRows)
    		throw "Cannot concatenate matrices, not same size" ;
    	// copy ourselves and then return the concatenated result
    	GdiMatrix		result(*this) ;
    
    	result.ConcatinateColumns(other) ;
    	return result ;
    }
    
    // concatinate the other matrix to ourselves
    void GdiMatrix::ConcatinateColumns(const GdiMatrix &other)
    {
    	if (m_NumRows != other.m_NumRows)
    		throw "Cannot concatenate matrices, not same size" ;
    	// create a matrix big enough to hold both
    	GdiMatrix		result(m_NumColumns + other.m_NumColumns, m_NumRows) ;
    
    	// now populate it
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			result.SetElement(i, j, GetElement(i, j)) ;
    			}
    		}
    	// now add the other matrix
    	for (int i = 0 ; i < other.m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			result.SetElement(i + m_NumColumns, j, other.GetElement(i, j)) ;
    			}
    		}
    	*this = result ;					// assign it to us
    }
    
    GdiMatrix GdiMatrix::GetConcatinatedRows(const GdiMatrix& other) const
    {
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Cannot concatenate matrices, not same size" ;
    	// copy ourselves and then return the concatenated result
    	GdiMatrix		result(*this) ;
    
    	result.ConcatinateRows(other) ;
    	return result ;
    }
    
    void GdiMatrix::ConcatinateRows(const GdiMatrix &other)
    {
    	if (m_NumColumns != other.m_NumColumns)
    		throw "Cannot concatenate matrices, not same size" ;
    	// create a matrix big enough to hold both
    	GdiMatrix		result(m_NumColumns, m_NumRows + other.m_NumRows) ;
    
    	// now populate it
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			result.SetElement(i, j, GetElement(i, j)) ;
    			}
    		}
    	// now add the other matrix
    	for (int i = 0 ; i < other.m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			result.SetElement(i, j + m_NumRows, other.GetElement(i, j)) ;
    			}
    		}
    	*this = result ;					// assign it to us
    }
    
    void GdiMatrix::AddColumn(const double *pData)
    {
    	ASSERT(FALSE == IsBadReadPtr(pData, sizeof(double) * m_NumRows)) ;
    
    	GdiMatrix	result(m_NumColumns + 1, m_NumRows) ;			// costruct the result
    
    	result.SetSubMatrix(0, 0, *this) ;				// copy ouselves across
    	// now add the new row
    	for (int i = 0 ; i < m_NumRows ; ++i)
    		{
    		result.SetElement(m_NumColumns, i, pData[i]) ;
    		}
    	*this = result ;								// assign result to us
    }
    
    void GdiMatrix::AddRow(const double *pData)
    {
    	ASSERT(FALSE == IsBadReadPtr(pData, sizeof(double) * m_NumColumns)) ;
    
    	GdiMatrix	result(m_NumColumns, m_NumRows + 1) ;			// costruct the result
    
    	result.SetSubMatrix(0, 0, *this) ;				// copy ouselves across
    	// now add the new row
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		result.SetElement(i, m_NumRows, pData[i]) ;
    		}
    	*this = result ;								// assign result to us
    }
    
    GdiMatrix	operator*(const GdiMatrix &other, double value)
    {
    	GdiMatrix copy(other) ;
    
    	// just multiply the elements by the value
    	for (int i = 0 ; i < copy.m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < copy.m_NumRows ; ++j)
    			{
    			copy.SetElement(i, j, copy.GetElement(i, j) * value) ;
    			}
    		}
    	return copy ;
    }
    
    GdiMatrix GdiMatrix::GetSquareMatrix() const
    {
    	GdiMatrix	copy(*this) ;
    
    	copy.MakeSquare() ;
    	return copy ;
    }
    
    void GdiMatrix::MakeSquare()
    {
    	// make the current matrix square by either stepping in the x or y directions
    	// square to the smallest side
    	int size = m_NumColumns ;
    	if (size > m_NumRows)
    		size = m_NumRows ;
    
    	GdiMatrix	work(size, size) ;				// construct result
    	double	x_step = m_NumColumns / size ;
    	double	y_step = m_NumRows / size ;
    
    	for (int i = 0 ; i < size ; ++i)
    		{
    		for (int j = 0 ; j < size ; ++j)
    			work.SetElement(i, j, GetElement((int)(i * x_step), (int)(j * y_step))) ;
    		}
    	*this = work ;				// copy the result to ourselves
    }
    
    GdiMatrix GdiMatrix::GetNormalised(double min, double max) const
    {
    	GdiMatrix copy(*this) ;
    	copy.Normalise(min, max) ;
    	return copy ;
    }
    
    void GdiMatrix::Normalise(double min, double max)
    {
    	// get the lower and upper limit values in the matrix
    	// we use the range to normalise
    	double	e_min ;
    	double	e_max ;
    
    	GetNumericRange(e_min, e_max) ;
    
    	double	range = e_max - e_min ;
    	double	r_range = max - min ;			// required range
    	double	value ;
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			value = GetElement(i, j) ;
    			value -= e_min ;			// 0 - range
    			value /= range ;
    			value *= r_range ;
    			value += min ;
    			SetElement(i, j, value) ;
    			}
    		}
    }
    
    // gets the lowest and highest values in the matrix
    void GdiMatrix::GetNumericRange(double &min, double &max) const
    {
    	double	e_min = GetElement(0, 0) ;
    	double	e_max = e_min ;
    	double	value ;
    
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		for (int j = 0 ; j < m_NumRows ; ++j)
    			{
    			value = GetElement(i, j) ;
    			if (value < e_min)
    				e_min = value ;
    			else if (value > e_max)
    				e_max = value ;
    			}
    		}
    	min = e_min ;
    	max = e_max ;
    }
    
    double GdiMatrix::SumColumn(int column) const
    {
    	ASSERT(column >= 0) ;					// bad column
    	ASSERT(column < m_NumColumns) ;				// bad column
    	double	sum = 0.0 ;
    
    	for (int i = 0 ; i < m_NumRows ; ++i)
    		sum += GetElement(column, i) ;
    	return sum ;
    }
    
    double GdiMatrix::SumRow(int row) const
    {
    	ASSERT(row >= 0) ;						// bad row
    	ASSERT(row < m_NumRows) ;					// bad row
    	double	sum = 0.0 ;
    
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		sum += GetElement(i, row) ;
    	return sum ;
    }
    
    double GdiMatrix::SumColumnSquared(int column) const
    {
    	double value = SumColumn(column) ;
    	return (value * value) ;
    }
    
    double GdiMatrix::SumRowSquared(int row) const
    {
    	double value = SumRow(row) ;
    	return (value * value) ;
    }
    
    // returns the minimum value in a row of the matrix
    double GdiMatrix::GetRowMin(int row) const
    {
    	ASSERT(row >= 0) ;
    	ASSERT(row < m_NumRows) ;
    	double	value = GetElement(0, row) ;
    	for (int i = 1 ; i < m_NumColumns ; ++i)
    		{
    		if (GetElement(i, row) < value)
    			value = GetElement(i, row) ;
    		}
    	return value ;
    }
    
    // returns the maximum value in a row of the matrix
    double GdiMatrix::GetRowMax(int row) const
    {
    	ASSERT(row >= 0) ;
    	ASSERT(row < m_NumRows) ;
    	double	value = GetElement(0, row) ;
    	for (int i = 1 ; i < m_NumColumns ; ++i)
    		{
    		if (GetElement(i, row) > value)
    			value = GetElement(i, row) ;
    		}
    	return value ;
    }
    
    // returns the minimum value in a column of the matrix
    double GdiMatrix::GetColumnMin(int column) const
    {
    	ASSERT(column >= 0) ;
    	ASSERT(column < m_NumColumns) ;
    	double	value = GetElement(column, 0) ;
    	for (int i = 1 ; i < m_NumRows ; ++i)
    		{
    		if (GetElement(column, i) < value)
    			value = GetElement(column, i) ;
    		}
    	return value ;
    }
    
    // returns the maximum value in a column of the matrix
    double GdiMatrix::GetColumnMax(int column) const
    {
    	ASSERT(column >= 0) ;
    	ASSERT(column < m_NumColumns) ;
    	double	value = GetElement(column, 0) ;
    	for (int i = 1 ; i < m_NumRows ; ++i)
    		{
    		if (GetElement(column, i) > value)
    			value = GetElement(column, i) ;
    		}
    	return value ;
    }
    
    // returns a row as , separated values
    CString GdiMatrix::GetRowAsText(int row) const
    {
    	ASSERT(row >= 0) ;						// bad row
    	ASSERT(row < m_NumRows) ;					// bad row
    	CString	text ;
    	CString	token ;
    
    	for (int i = 0 ; i < m_NumColumns ; ++i)
    		{
    		if (i > 0)
    			text += "," ;
    		token.Format("%e", GetElement(i, row)) ;
    		text += token ;
    		}
    	return text ;
    }
    
    // read a line of text from the current file
    CString GdiMatrix::ReadLine(CFile& file)
    {
    	CString	line("") ;
    	char	ch[3] ;
    	DWORD	hBytesRead	= 0 ;
    
    	while (true)
    		{
    		hBytesRead = file.Read(&ch[0], 2) ;
    		if (hBytesRead == 2)
    			file.Seek(-1L, CFile::current) ;		
    		if (hBytesRead == 0)
    			break ;					// end of file
    		if (ch[0] == '\n')
    			{
    			if (ch[1] == '\r')
    				file.Seek(1L, CFile::current) ;
    			break ;
    			}
    		if (ch[0] == '\r')
    			{
    			ch[0] = '\n' ;
    			if (ch[1] == '\n')
    				file.Seek(1L, CFile::current) ;
    			break ;
    			}
    		if (ch[0] != '\015')
    			{
    			// ignore LF characters
    			ch[1] = '\0' ;
    			line += ch ;
    			}
    		}
    	return line ;
    }
    
    int GdiMatrix::GetStringToken(CString source, CString &destination, int start, char ch)
    {
    	ASSERT(start >= 0) ;
    
    	// at the end of the source string ?
    	if (start >= source.GetLength())
    		{
    		destination = "" ;					// no token available
    		return source.GetLength() ;			// return @ end of string
    		}
    
    	// skip past any termination characters at the start position
    	while (start < source.GetLength())
    		{
    		if (ch == source[start])
    			start++ ;
    		else
    			break ;
    		}
    	// find the next occurance of the terminating character
    	int pos = source.Find(ch, start) ;			// find termination character
    	if (pos < 0)
    		{
    		// terminator not found, just return the remainder of the string
    		destination = source.Right(source.GetLength() - start) ;
    		return source.GetLength() ;
    		}
    	// found terminator, get sub string
    	destination = source.Mid(start, pos - start) ;
    	return pos ;
    }
    

    Fazit.. Du musst aus allen Verfahren das beste für Dich nutzen, keines der
    Maßnahmen erreicht ein ahha Erlebnis.

    Ich Rechteck-Forscher habe festgestellt, das es keine Kreise gibt. Das ist das eigentlich Problem ^^

    Viel Spass
    Karsten aus Preußen (www.FlexxVision.de)



  • Achromat schrieb:

    Alle Punkte...

    Schöne Übersicht mit welchen Ansätzen man das Problem angehen kann.
    Auch den Codestil passt zum Alter des Threads, den den du nach mehr als 13 Jahren so unsanft wieder ins Leben zurückgerissen hast (SCNR) 😛

    Finnegan

    P.S.: Erste Aussage ist aufrichtig gemeint. Interessante Ideensammlung!



  • Hi,

    ja das ist richtig, denn wieder mal kommt es zur direkten Konfrontation mit diesem leidigen Kreis. Gerade in der Messbilderfassung über Sensoren erhält man schöne Kreise mit auch Fehlerhaften stellen. Und dann geht das Theater wieder von vorne los.. Einige Methoden sind nicht anwendbar andere Methoden schnell zu Rechenlastig.

    Ja Oldscool Code , was sonnst.. man kann doch infernalste Vorgänge keiner allgemeinen Lösung zum Fraße reichen, man würde scheitern.

    Aber das ist wirklich nur ein wildes Samarium aus Tests und alten Wiedergängern.

    Man findet aber die Message in dem Gedünst..

    "Mami, Mami, ich will nicht länger im Kreis rumlaufen!"
    "Halt´s Maul oder ich nagel deinen anderen Fuß auch noch fest!"


Anmelden zum Antworten