| Class TCubeSpin (unit Ccube) |
TPanel
| Constructors |
Constructor Create(AOwner:TComponent);| Functions |
Destructor Destroy;
Procedure SetAngles( AX,AY,AZ :Integer);
procedure SetContinuous( newValue:Boolean);
procedure SetOptions( newValue :TCubeDispOpts);
procedure SetXSpin( newValue :Integer);
procedure SetYSpin( newValue :Integer);
procedure SetZSpin( newValue :Integer);
procedure Paint;Windows calls here to ask us to repaint
procedure BMPDraw;
procedure Connect(dc:HDC; V1,V2:Integer);
procedure DrawCube;
procedure DrawEdges(dc:HDC);
procedure DrawFaces(c:TCanvas);
procedure LinetoPt(dc:HDC; P:TPoint);
function MapPt(Vertex:Integer):TPoint;
procedure MovetoPt(dc:HDC; P:TPoint);
function Rotate(P:TPoint; Rotation:Integer):TPoint;
function Rotate2D(P:TPoint; Rotation:Integer):TPoint;
function Rotate3D(Const P:TPoint3D):TPoint3D;
function Rotate3D2(Const P:TPoint3D):TPoint3D;
function Rotate3D3(Const P:TPoint3D):TPoint3D;Now use it!
procedure RotateCube;
procedure SetSize;
procedure TimerElapse(Sender: TObject);
procedure WMEnterIdle(var Message: TWMEnterIdle);
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd);
procedure WMSize(var Message: TWMSize);
Procedure XFormBld;| Properties |
property Continuous : Boolean
property Options : TCubeDispOpts
property SpinInc : Integer
property XSpin : Integer
property XSpinOn : Boolean
property YSpin : Integer
property YSpinOn : Boolean
property ZSpin : Integer
property ZSpinOn : Boolean| Events |
event OnSpin : TNotifyEvent| Variables |
Probs : TStrings;
AngleX : Integer;
AngleY : Integer;
AngleZ : Integer;
BMPCanvas : TCanvas;
CubeBMP : HBITMAP;
fContinuous : Boolean;
fForceErase : Boolean;
fOnSpin : TNotifyEvent;
fOptions : TCubeDispOpts;
fSpinInc : Integer;
fTimer : TTimer;
fUpdating : Boolean;
fXSpinOn : Boolean;
fYSpinOn : Boolean;
fZSpinOn : Boolean;
HideV : Integer;
LastV : Integer;
Perspective : Integer;
ScaleMe : Integer;
Vertices : Array [0..7] of TPoint3d;
VRotated : Array [0..7] of TPoint3d;
XForm3d : Array [0..3,0..3] of Single;
XP : Integer;
YP : Integer;
ZScale : Integer;| Constructors |
Constructor Create(AOwner:TComponent);ReleaseDC(0, ScreenDC);
| Functions |
Destructor Destroy;SetSize;
Procedure SetAngles( AX,AY,AZ :Integer);Downscale Z-Axis values by this } { Create a bitmap to handle smooth redraws
procedure SetContinuous( newValue:Boolean);Faces requires hidden line removal
procedure SetOptions( newValue :TCubeDispOpts);
procedure SetXSpin( newValue :Integer);Request a Redraw
procedure SetYSpin( newValue :Integer);
procedure SetZSpin( newValue :Integer);
procedure Paint;Protected declarations
Windows calls here to ask us to repaint
procedure BMPDraw;
procedure Connect(dc:HDC; V1,V2:Integer);Draw a line from the last point to this point. Also does 3D to 2D mapping and limited hidden line removal.
procedure DrawCube;Draw the Sides
procedure DrawEdges(dc:HDC);Come here to draw the cube by it's edges
procedure DrawFaces(c:TCanvas);Come here to draw the cube by it's faces
procedure LinetoPt(dc:HDC; P:TPoint);Does a GDI lineto using a point instead of X,Y coords
function MapPt(Vertex:Integer):TPoint;Take a 3D Point (vertex #) and map it to the 2D screen
procedure MovetoPt(dc:HDC; P:TPoint);Does a GDI moveto using a point instead of X,Y coords
function Rotate(P:TPoint; Rotation:Integer):TPoint;Rotate a point by transforming it from rectangular to polar, adjusting the polar angle, and transforming it back. This was WAY too slow and was replaced with the 2D transformation matrix approach below
function Rotate2D(P:TPoint; Rotation:Integer):TPoint;2D Rotation via transform matrix: [ cos A, sin A, 0 ] general [ a b 0 ] [ -sin A, cos A, 0 ] [ c d 0 ] [ 0, 0, 0 ] [ tx ty 1 ] or X' := aX + bY + tx := (cos A)X + (sin A)Y; Y' := cX + dY + ty := (-sin A)X + (cos A)Y;
function Rotate3D(Const P:TPoint3D):TPoint3D;Do a 3D rotate by performing 2D rotates around each axis. This is probably much slower than using a 3D transformation Matrix, but I've been too lazy to figure out what a three-D transformation Matrix would look like.
function Rotate3D2(Const P:TPoint3D):TPoint3D;Do a 3D rotate by using a 3D transformation Matrix: [ cos Az * cos Ay, sin Az, -sin Ay, 0 ] general [ a b c 0 ] [ -sin Az, cos Az * cos Ax, sin Ax, 0 ] [ d e f 0 ] [ sin Ay, -sin Ax, cos Ax * cos Ay, 0 ] [ g h i 0 ] [ 0, 0, 0, 1 ] [ tx ty tz 1 ] or X' := aX + bY + cZ + tx := (cos Az)(cos Ay)X + (sin Az)Y - (sin Ay)Z; Y' := dX + eY + fZ + ty := (-sin Az)X + (cos Az)(cos Ax)Y + (sin Ax)Z; Z' := fX + gY + hZ + ty := (sin Ay)X -(sin Ax)Y + (cos Ax)(cos Ay)Z; [ cosY*cosZ cosY*-sinZ -sinY 0 ] [ -sinXsinY*cosZ+cosX*sinZ -sinXsinY*-sinZ+cosX*cosZ -sinXcosY 0 ] [ cosXsinY*cosZ+sinX*sinZ cosXsinY*-sinZ+sinX*cosZ cosXcosY 0 ] [ 0 0 0 1 ] or X' = cosAY*cosAZ*X - cosAY*sinAZ*Y - sinAY*Z Y' = (-sinAX*sinAY*cosAZ + cosAX*sinAZ)*X + (sinAX*sinAY*sinAZ+cosAX*cosAZ)Y - sinAX*cosAY*Z Z' = (cosAX*sinAY*cosAZ+sinAX*sinAZ)*X + (-cosAX*sinAY*sinAZ+sinAX*cosAZ)Y + (cosAX*cosAY)Z
function Rotate3D3(Const P:TPoint3D):TPoint3D;Precompute Transformation Matrix
Now use it!
procedure RotateCube;Rotate the Cube to the correct angles, then Check for hidden line removal and process
procedure SetSize;Builds a cube of the proper size, and allocates a bitmap of the correct size for double buffering
procedure TimerElapse(Sender: TObject);Not our window that was resized
procedure WMEnterIdle(var Message: TWMEnterIdle);Else Inherited;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd);Suppress Windows normal background erasure. If we're double buffering, then we always paint the whole area, so erasing the background would cause unnecessary flicker. If we're not double buffering, then we let the normal erase occur (which DOES cause flicker), unless the user has turned off erasing.
procedure WMSize(var Message: TWMSize);Trap the Windows message requesting our size change, let it, then recreate the bitmap drawing buffer, resize the cube, and request a redraw
Procedure XFormBld;NewPt := Rotate3d(P); If (Abs(NewPt.X-Result.X)>2) or (Abs(NewPt.Y-Result.Y)>2) or (Abs(NewPt.Z-Result.Z)>2) Then { Raise Exception.Create( } Probs.Add( Format( 'No match on X %3d:%4d ->%4d %4d, Y %3d:%4d ->%4d %4d, Z %3d:%4d ->%4d %4d', [AngleX,P.X,Result.X,NewPt.X, AngleY,P.Y,Result.Y,NewPt.Y, AngleZ,P.Z,Result.Z,NewPt.Z ])); (
| Properties |
property Continuous : Boolean
property Options : TCubeDispOpts
property SpinInc : Integer
property XSpin : IntegerPublished declarations
property XSpinOn : Boolean
property YSpin : Integer
property YSpinOn : Boolean
property ZSpin : Integer
property ZSpinOn : Boolean| Events |
event OnSpin : TNotifyEvent| Variables |
Probs : TStrings;Public declarations
AngleX : Integer;
AngleY : Integer;Y/Z Rotation about X
AngleZ : Integer;X/Z Rotation about Y
BMPCanvas : TCanvas;Cache the bitmap for redraw speed
CubeBMP : HBITMAP;Last Drawn Vector
fContinuous : Boolean;
fForceErase : Boolean;
fOnSpin : TNotifyEvent;
fOptions : TCubeDispOpts;
fSpinInc : Integer;
fTimer : TTimer;Updating Controls
fUpdating : Boolean;
fXSpinOn : Boolean;X/Y Rotation about Z
fYSpinOn : Boolean;
fZSpinOn : Boolean;
HideV : Integer;
LastV : Integer;Hidden vertex
Perspective : Integer;
ScaleMe : Integer;
Vertices : Array [0..7] of TPoint3d;Private declarations
VRotated : Array [0..7] of TPoint3d;
XForm3d : Array [0..3,0..3] of Single;
XP : Integer;
YP : Integer;
ZScale : Integer;Scaling up from 1