unit maprotation_unit; { procedures for bitmap rotation source bitmap is rotated to destination bitmap center of bitmap is also center of rotation bitmaps must be created / destroyed by other unit how to proceed: 1. create source and destination bitmaps set width, height of source map 2. call setmaps(sourcemap,destinationmap) to set - pixelformat to pf32bit - size of destinationmap to accomodate all rotations of source map 3. a. paint or draw in sourcemap call coarse|medium|finerotate(angle) to rotate source to destination b. load sourcemap from file call setmaps(sourcemap,destinationmap) to adjust size of destination map call coarse|medium|finerotate(angle) to rotate source to destination note: angle is in degrees (0..360) work: 1 - 11 - 2013 coarse/medium : for loop for quadrants, common code function removed 4 - 11 - 2013 fine rotate code added } interface uses graphics,types; procedure setmaps(sm,dm : Tbitmap); procedure CoarseRotate(deg : word); procedure mediumRotate(deg : word); procedure FineRotate(deg : word); implementation type PDW = ^dword; Toffset = record fx : single; fy : single; end; const deg2rad = pi/180; var SBM,DBM : Tbitmap; dcxy : word; //destination center x = y scx,scy : word; //center of source map PSBM : dword; //pointer to source map Slinestep : dword; //pointer difference between rows PDBM : dword; //pointer to destination map Dlinestep : dword; //... // offset : array[1..4,0..8] of Toffset;//fine rotate offsets per quadrant procedure setmaps(sm,dm : Tbitmap); //select source bitmap, adjust size of destination map var w,h : single; begin SBM := sm; SBM.PixelFormat := pf32bit; DBM := dm; DBM.PixelFormat:= pf32bit; DBM.Canvas.Brush.Color := $ffffff; scx := (SBM.width-1) div 2; scy := (SBM.height-1) div 2; w := SBM.width; h := SBM.height; DBM.Width := trunc(sqrt( w*w + h*h)+2) or 1;//set odd dimensions DBM.Height := DBM.Width; dcXY := DBM.width div 2; PSBM := dword(sbm.scanline[0]); Slinestep := PSBM - dword(sbm.scanline[1]); PDBM := dword(dbm.scanline[0]); Dlinestep := PDBM - dword(dbm.scanline[1]); end; procedure CoarseRotate(deg : word); //fast rotation //scan pixels of source map and copy to destination map var x,y,tx,ty,tt : word; xtx,xty,ytx,yty : single; radians,vsin,vcos : single; pix,Ybase1,Ybase2,PS,PD : dword; i : byte; begin with dbm do with canvas do begin brush.Style := bsSolid; fillrect(rect(0,0,width,height)); //erase with existing brush end; radians := deg*deg2rad; vsin := sin(radians); vcos := cos(radians); for y := 0 to scy do begin yty := y*vcos; ytx := y*vsin; Ybase1 := PSBM - (scy + y)*Slinestep; tt := scy - y; Ybase2 := PSBM - tt*Slinestep; for x := 0 to scx do begin xtx := x*vcos; xty := x*vsin; for i := 1 to 4 do begin case i of 1 : begin tx := dcxy + trunc(xtx - ytx); ty := dcxy + trunc(xty + yty); tt := scx + x; PS := Ybase1 + (tt shl 2); end; 2 : begin tt := scx - x; PS := Ybase1 + (tt shl 2); tx := dcxy + trunc(-xtx - ytx); ty := dcxy + trunc(-xty + yty); end; 3 : begin PS := Ybase2 + (tt shl 2); tx := dcxy + trunc(-xtx + ytx); ty := dcxy + trunc(-xty - yty); end; 4 : begin tt := scx + x; PS := Ybase2 + (tt shl 2); tx := dcxy + trunc(xtx + ytx); ty := dcxy + trunc(xty - yty); end; end;//case pix := PDW(PS)^; PD := PDBM - ty*Dlinestep + (tx shl 2); PDW(PD)^ := pix; end;//for i // end;//for x end;//for y end; procedure mediumrotate(deg : word); //medium quality rotation //scan pixels of destination map and copy from source map var x,y,tt : word; tx,ty,xtx,xty,ytx,yty : single; radians,vsin,vcos : single; pix,Ybase1,Ybase2,PS,PD,colr : dword; ttx,tty : word; trunctx,truncty : smallInt; var i : byte; begin colr := DBM.canvas.brush.color; radians := deg2rad*deg; vsin := sin(radians); vcos := cos(radians); for y := 0 to dcxy do begin yty := y*vcos; ytx := y*vsin; Ybase1 := PDBM - (dcxy + y)*Dlinestep; tt := dcxy - y; Ybase2 := PDBM - tt*Dlinestep; for x := 0 to dcxy do begin xtx := x*vcos; xty := x*vsin; // for i := 1 to 4 do //for all quadrants begin case i of 1 : begin PD := Ybase1 + ((dcxy+x) shl 2); tx := xtx + ytx; ty := -xty + yty; end; 2 : begin tt := dcxy - x; PD := Ybase1 + (tt shl 2); tx := -xtx + ytx; ty := xty + yty; end; 3 : begin PD := Ybase2 + (tt shl 2); tx := -xtx - ytx; ty := xty - yty; end; 4 : begin PD := Ybase2 + ((dcxy + x) shl 2); tx := xtx - ytx; ty := -xty - yty; end; end;//case trunctx := trunc(tx); truncty := trunc(ty); if (abs(trunctx) > scx) or (abs(truncty) > scy) then PDW(PD)^ := colr else begin ttx := scx + trunctx; tty := scy + truncty; PS := PSBM - tty*Slinestep + (ttx shl 2); pix := PDW(PS)^; PDW(PD)^ := pix; end; end;//for i // end;//for x end;//for y end; procedure FineRotate(deg : word); //hi quality rotation //scan destination map per quarter bit and copy from source map var x,y,tt : word; tx,ty,xtx,xty,ytx,yty : single; radians,vsin,vcos : single; pix,Ybase1,Ybase2,PS,PD,colr : dword; ttx,tty : word; trunctx,truncty : smallInt; i,j,quad : byte; vi,vj : single; sumR,sumG,sumB : word; //color sums bgR,bgG,bgB : byte; begin colr := DBM.canvas.brush.color; bgR := (colr shr 16) and $ff; bgG := (colr shr 8) and $ff; bgB := colr and $ff; radians := deg2rad*deg; vsin := sin(radians); vcos := cos(radians); // build offset table for j := 0 to 2 do //offsets y begin vj := 0.333*j; yty := vj*vcos; ytx := vj*vsin; for i := 0 to 2 do // x begin vi := 0.333*i; xtx := vi*vcos; xty := vi*vsin; for quad := 1 to 4 do with offset[quad,i + 3*j] do case quad of 1 : begin fx := xtx + ytx; fy := -xty + yty; end; 2 : begin fx := -xtx + ytx; fy := xty + yty; end; 3 : begin fx := -xtx - ytx; fy := xty - yty; end; 4 : begin fx := xtx - ytx; fy := -xty - yty; end; end;//case end;//for j end;//for i // pixel scanning for y := 0 to dcxy do begin yty := y*vcos; ytx := y*vsin; Ybase1 := PDBM - (dcxy + y)*Dlinestep; tt := dcxy - y; Ybase2 := PDBM - tt*Dlinestep; for x := 0 to dcxy do begin xtx := x*vcos; xty := x*vsin; // for i := 1 to 4 do //for all quadrants begin case i of 1 : begin PD := Ybase1 + ((dcxy+x) shl 2); tx := xtx + ytx; ty := -xty + yty; end; 2 : begin tt := dcxy - x; PD := Ybase1 + (tt shl 2); tx := -xtx + ytx; ty := xty + yty; end; 3 : begin PD := Ybase2 + (tt shl 2); tx := -xtx - ytx; ty := xty - yty; end; 4 : begin PD := Ybase2 + ((dcxy + x) shl 2); tx := xtx - ytx; ty := -xty - yty; end; end;//case // subpixel scanning sumR := 0; sumG := 0; sumB := 0; for j := 0 to 8 do begin trunctx := trunc(tx + offset[i,j].fx); truncty := trunc(ty + offset[i,j].fy); if (abs(trunctx) > scx) or (abs(truncty) > scy) then begin sumR := sumR + bgR; sumG := sumG + bgG; sumB := sumB + bgB; end else begin ttx := scx + trunctx; tty := scy + truncty; PS := PSBM - tty*Slinestep + (ttx shl 2); pix := PDW(PS)^; sumR := sumR + ((pix shr 16) and$ff); sumG := sumG + ((pix shr 8) and $ff); sumB := sumB + (pix and $ff); end; end;//for j sumR := sumR div 9; sumG := sumG div 9; sumB := sumB div 9; pix := (sumR shl 16) or (sumG shl 8) or sumB; PDW(PD)^ := pix; end;//for i quadrants // end;//for x end;//for y end; end.