2005. augusztus 28., vasárnap

Simple way to rotate region

Problem/Question/Abstract:

Simple function returning rotated region. Pprocedure doing the same with source region.

It's the simple function returning new region rotated to the angle that you want around the source region. Source region doesn't change.

The second procedure does the same with source region without creating new region.

I hope this will be useful.
Comments are provided along the code

function _RotateRgn(ARgn: HRGN; ADegree: Real): HRGN;
var
wXFORM: XFORM; // transformation structure, see Windows API
kRgnD: DWord; // count of RGNDATA structures in region
RgnData: PRgnData; // pointer to region data
Rt: TRect;
kX, kY: Integer;
begin
if (ARgn = 0) or (ADegree = 0) then
Exit;

// Get region's surrounding rectangular
GetRgnBox(ARgn, Rt);

// Move source region so that the centre of its surrounding rectangular
// goes to the left top corner of a window
kX := Rt.Left + (Rt.Right - Rt.Left) div 2;
kY := Rt.Top + (Rt.Bottom - Rt.Top) div 2;
OffsetRgn(ARgn, -kX, -kY);

// Fill XFORM according to task (rotate region)
FillChar(wXFORM, SizeOf(wXFORM), #0);
wXFORM.eM11 := Cos(ADegree / 180 * pi);
wXFORM.eM12 := -Sin(ADegree / 180 * pi);
wXFORM.eM21 := -wXFORM.eM12;
wXFORM.eM22 := wXFORM.eM11;

// Prepare buffer to store region data
kRgnD := GetRegionData(ARgn, 0, nil);
GetMem(RgnData, SizeOf(RGNDATA) * kRgnD);
// ..and fill the buffer with region's data
GetRegionData(ARgn, kRgnD, RgnData);
// ..move source region to its initial position
OffsetRgn(ARgn, kX, kY);

// Create output region using data in the buffer and transformation wXFORM
Result := ExtCreateRegion(@wXFORM, kRgnD, RgnData^);
// Move output region on a place of source region
OffsetRgn(Result, kX, kY);
FreeMem(RgnData);
end;

procedure _RotateRgnEx(var ARgn: HRGN; ADegree: Real);
var
wXFORM: XFORM; // transformation structure, see Windows API
kRgnD: DWord; // count of RGNDATA structures in region
RgnData: PRgnData; // pointer to region data
Rt: TRect;
kX, kY: Integer;
begin
if (ARgn = 0) or (ADegree = 0) then
Exit;

// Get region's surrounding rectangular
GetRgnBox(ARgn, Rt);

// Move source region so that the centre of its surrounding rectangular
// goes to the left top corner of a window
kX := Rt.Left + (Rt.Right - Rt.Left) div 2;
kY := Rt.Top + (Rt.Bottom - Rt.Top) div 2;
OffsetRgn(ARgn, -kX, -kY);

// Fill XFORM according to task (rotate region)
FillChar(wXFORM, SizeOf(wXFORM), #0);
wXFORM.eM11 := Cos(ADegree / 180 * pi);
wXFORM.eM12 := -Sin(ADegree / 180 * pi);
wXFORM.eM21 := -wXFORM.eM12;
wXFORM.eM22 := wXFORM.eM11;

// Prepare buffer to store region data
kRgnD := GetRegionData(ARgn, 0, nil);
GetMem(RgnData, SizeOf(RGNDATA) * kRgnD);
// ..and fill the buffer with region's data
GetRegionData(ARgn, kRgnD, RgnData);
// ..delete source region
DeleteObject(ARgn);

// Create new region using data in the buffer and transformation wXFORM
ARgn := ExtCreateRegion(@wXFORM, kRgnD, RgnData^);
// Move output region to the origin place
OffsetRgn(ARgn, kX, kY);
FreeMem(RgnData);
end;