Mirror

Simple way to rotate region (Views: 706)


Problem/Question/Abstract:

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

Answer:

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;

<< Back to main page