Ну вот например по вдохновению ссылкой Dedekinda за час на Delphi была сделана такая визуализация
https://youtu.be/btfPS1CXiA0Исходники:
Код:
// в "Вероятности на алгебрах 1965" на стр.24 упомянута "хорошо известная"
// группа преобразований, образованная дробно-линеынйми функциями
// (z1+z)/(1+сопряж(z1)*z)
// для визуализации этого преобразования и созданно данное приложение
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.Imaging.jpeg,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
ImageIn: TImage;
ImageOut: TImage;
Panel1: TPanel;
StaticText1: TStaticText;
Button1: TButton;
PaintBox1: TPaintBox;
Timer1: TTimer;
Image1: TImage;
PaintBox2: TPaintBox;
Image2: TImage;
procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Panel1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Transformation(za,zb:extended;var newX,newY:extended);
procedure Retransformation(za,zb:extended;var newX,newY:extended);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormClick(Sender: TObject);
private
{ Private declarations }
z1a,z1b:extended;
Bitmap1,Bitmap2:TBitmap;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
W = 640; // ширина PaintBox
H = 512; // высота PaintBox
var
// массив пикселей (можно динамический, но там чуть сложнее)
Bits1: array[0..H-1,0..W-1] of TColor;
BitsInfo1: BITMAPINFO;
Bits2: array[0..H-1,0..W-1] of TColor;
BitsInfo2: BITMAPINFO;
// отрисовка массива на устройство DC:
function DrawToDC1(DC: HDC; X, Y, Width, Height: Integer): Integer;
begin
with BitsInfo1.bmiHeader do
begin
biWidth := Width;
biHeight := -Height;
end;
Result := SetDIBitsToDevice(
DC,
X, Y, Width, Height,
0, 0, 0, Height,
@Bits1, BitsInfo1, DIB_RGB_Colors
);
end;
// рисуем точку
procedure Plot1(x,y: Integer; C: TColor);
begin
if (x>=0) and (y>=0) and (x<W) and (y<H) then begin
Bits1[y,x] := C;
end;
end;
// отрисовка массива на устройство DC:
function DrawToDC2(DC: HDC; X, Y, Width, Height: Integer): Integer;
begin
with BitsInfo2.bmiHeader do
begin
biWidth := Width;
biHeight := -Height;
end;
Result := SetDIBitsToDevice(
DC,
X, Y, Width, Height,
0, 0, 0, Height,
@Bits2, BitsInfo2, DIB_RGB_Colors
);
end;
// рисуем точку
procedure Plot2(x,y: Integer; C: TColor);
begin
if (x>=0) and (y>=0) and (x<W) and (y<H) then begin
Bits2[y,x] := C;
end;
end;
var first:boolean=true;
procedure TForm1.Retransformation(za,zb:extended;var newX,newY:extended);
var upA,upB,downA,downB,norma:extended;
begin
upA:=za-z1a;
upB:=zb-z1b;
downA:=1-(z1a*za+z1b*zb);
downB:=-(z1a*zb-z1b*za);
norma:=downA*downA+downB*downB;
if norma=0 then
begin
if (upA*downA+upB*downB)=0 then newX:=1 else newX:=0;
if (upB*downA-upA*downB)=0 then newY:=1 else newY:=0;
end else
begin
newX:=(upA*downA+upB*downB)/norma;
newY:=(upB*downA-upA*downB)/norma;
end;
end;
function getRGB(oldX,oldY:extended;mode:byte):TColor;
var modul,arg:extended;
re,ge,be:extended;
r,g,b:byte;
begin
modul:=sqrt(oldX*oldX+oldY*oldY);
if modul=0 then modul:=0.000000000000001;
if (oldX=0)and(oldY=0) then arg:=0 else;
if (oldX>0)and(oldY=0) then arg:=0 else
if (oldX>0)and(oldY>0) then arg:=ArcTan(oldY/oldX) else
if (oldX=0)and(oldY>0) then arg:=pi/2 else
if (oldX<0)and(oldY>0) then arg:=pi-ArcTan(-oldY/oldX) else
if (oldX<0)and(oldY=0) then arg:=pi else
if (oldX<0)and(oldY<0) then arg:=pi+ArcTan(oldY/oldX) else
if (oldX=0)and(oldY<0) then arg:=pi+pi/2 else
if (oldX>0)and(oldY<0) then arg:=2*pi-ArcTan(-oldY/oldX);
re:=55*ln(1+(modul/1412)*255*2*abs(0.5-(arg-0)/(2*pi)));
ge:=55*ln(1+(modul/1412)*255*2*abs(0.5-abs(arg-2*pi/3)/(2*pi)));
be:=55*ln(1+(modul/1412)*255*2*abs(0.5-abs(arg-2*2*pi/3)/(2*pi)));
if re>255 then re:=255;
if ge>255 then ge:=255;
if be>255 then be:=255;
r:=round(int(re));
g:=round(int(ge));
b:=round(int(be));
if mode=1 then
result:=RGB(r,g,b) else
result:=RGB(b,g,r);
end;
procedure DrawPixelFast(Bitmap: TBitmap; X, Y: Integer; Color: TColor);
var
ScanLine: PByteArray;
BytesPerPixel: Integer;
begin
if (X < 0) or (X >= Bitmap.Width) or (Y < 0) or (Y >= Bitmap.Height) then
Exit;
BytesPerPixel := 3;//Bitmap.PixelFormat div 8;
ScanLine := Bitmap.ScanLine[Y];
// Проверка на случай использования палитры (PixelFormat = pf8Bit)
if BytesPerPixel = 1 then
ScanLine[X] := ColorToRGB(Color)
else
begin
ScanLine[X * BytesPerPixel] := GetBValue(Color);
ScanLine[X * BytesPerPixel + 1] := GetGValue(Color);
ScanLine[X * BytesPerPixel + 2] := GetRValue(Color);
//if BytesPerPixel = 4 then
// ScanLine[X * BytesPerPixel + 3] := GetAValue(Color);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var x,y:integer;
oldX,oldY,newX,newY:extended;
c:TColor;
begin
if first then
begin
Bitmap1 := TBitmap.Create;
Bitmap1.Width := ImageIn.Picture.Bitmap.Width;
Bitmap1.Height := ImageIn.Picture.Bitmap.Height;
Bitmap1.PixelFormat := pf24bit;
Bitmap2 := TBitmap.Create;
Bitmap2.Width := ImageOut.Picture.Bitmap.Width;
Bitmap2.Height := ImageOut.Picture.Bitmap.Height;
Bitmap2.PixelFormat := pf24bit;
end;
for x := 0 to ImageIn.Picture.Bitmap.Width do
for y := 0 to ImageIn.Picture.Bitmap.Height do
begin
oldX:=2*(x-ImageIn.Picture.Bitmap.Width/2);
oldY:=2*(ImageIn.Picture.Bitmap.Height/2-y);
if first then
begin
c:=getRGB(oldX,oldY,1);
//ImageIn.Picture.Bitmap.Canvas.Pixels[x,y]:=c;
DrawPixelFast(Bitmap1, x, y, c);
end;
transformation(oldX,oldY,newX,newY);
c:=getRGB(newX,newY,2);
//ImageOut.Picture.Bitmap.Canvas.Pixels[x,y]:=c;
///}DrawPixelFast(Bitmap2, x, y, c);
{!}Plot1(x, y, c);
retransformation(oldX,oldY,newX,newY);
c:=getRGB(newX,newY,2);
Plot2(x, y, c);
end;
if first then
begin
ImageIn.Picture.Bitmap.Assign(Bitmap1);
first:=false;
end;
///}ImageOut.Picture.Bitmap.Assign(Bitmap2);
{!}DrawToDC1(PaintBox1.Canvas.Handle, 0, 0, W, H);
DrawToDC2(PaintBox2.Canvas.Handle, 0, 0, W, H);
// Bitmap1.Free;
// Bitmap2.Free;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
close;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
jpeg:TJpegImage;
bmp:TBitmap;
begin
{ jpeg:=TJpegImage.Create;
bmp:=TBitmap.Create;
jpeg.LoadFromFile('1.jpg');
bmp.Assign(jpeg);
jpeg.Free;
//рисуем на канве битмапа
bmp.Canvas.Rectangle(0,0,100,100); //что рисовать не важно
bmp.Free; }
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
timer1.Enabled:=false;
//MouseMove([],512,640);
SetCursorPos(824,664);
Button1.Click;
end;
procedure TForm1.Transformation(za,zb:extended;var newX,newY:extended);
var upA,upB,downA,downB,norma:extended;
begin
upA:=z1a+za;
upB:=z1b+zb;
downA:=1+z1a*za+z1b*zb;
downB:=z1a*zb-z1b*za;
norma:=downA*downA+downB*downB;
if norma=0 then
begin
if (upA*downA+upB*downB)=0 then newX:=1 else newX:=0;
if (upB*downA-upA*downB)=0 then newY:=1 else newY:=0;
end else
begin
newX:=(upA*downA+upB*downB)/norma;
newY:=(upB*downA-upA*downB)/norma;
end;
end;
procedure TForm1.Panel1Click(Sender: TObject);
var x,y,tx,ty:integer;
oldX,oldY,newX,newY:extended;
c:TColor;
begin
timer1.Enabled:=true;
exit;
//ImageIn.Invalidate;
for x := 0 to round(int(ImageIn.Picture.Bitmap.Width/10)) do
for y := 0 to round(int(ImageIn.Picture.Bitmap.Height/10)) do
begin
c:=ImageIn.Picture.Bitmap.Canvas.Pixels[10*x,10*y];
oldX:=(10*x-ImageIn.Picture.Bitmap.Width/2)/0.9;
oldY:=(ImageIn.Picture.Bitmap.Height/2-10*y)/0.9;
transformation(oldX,oldY,newX,newY);
tx:=round(int(ImageIn.Picture.Bitmap.Width/2+9*newX));
ty:=round(int(ImageIn.Picture.Bitmap.Height/2-9*newY));
//ImageOut.Picture.Bitmap.Canvas.Pixels[tx,ty]:=c;
ImageOut.Picture.Bitmap.Canvas.MoveTo(10*x,10*y);
ImageOut.Picture.Bitmap.Canvas.LineTo(tx,ty);
end;
//ImageIn.Update;
//ImageOut.Repaint;
end;
procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var sx,sy:string;
begin
z1a:=(X-320/2)/20000;
z1b:=(256/2-Y)/20000;
Str(z1a*100:2:2,sx);
Str(z1b*100:2:2,sy);
if (z1a>=0)and(z1b>=0) then StaticText1.Caption:='z₁:=+'+sx+'+'+sy+'i' else
if (z1a< 0)and(z1b< 0) then StaticText1.Caption:='z₁:='+sx+sy+'i' else
if (z1a< 0)and(z1b>=0) then StaticText1.Caption:='z₁:='+sx+'+'+sy+'i' else
StaticText1.Caption:='z₁:=+'+sx+sy+'i';
Button1.Click();
end;
initialization
with BitsInfo1, bmiHeader do
begin
biSize := SizeOf (bmiHeader);
biWidth := 0;
biHeight := 0;
biPlanes := 1;
biBitCount := 32;
biCompression := BI_RGB;
biSizeImage := 0;
biXPelsPerMeter := 0;
biYPelsPerMeter := 0;
biClrUsed := 0;
biClrImportant := 0;
end;
with BitsInfo2, bmiHeader do
begin
biSize := SizeOf (bmiHeader);
biWidth := 0;
biHeight := 0;
biPlanes := 1;
biBitCount := 32;
biCompression := BI_RGB;
biSizeImage := 0;
biXPelsPerMeter := 0;
biYPelsPerMeter := 0;
biClrUsed := 0;
biClrImportant := 0;
end;
//MessageBox(0,'клик на белом для выхода, клик на сером для центровки','',0);
end.