• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

gisoracle

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

最小包络矩形的算法和代码

最小包络矩形的算法和代码

unit Unit1;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls;

type
    TPolyVertex = record                //浮点型顶点定义
        X: Double;
        Y: Double
    end;

    TMinRect = record                   //矩形记录
        p1: TPolyVertex;
        p2: TPolyVertex;
        p3: TPolyVertex;
        p4: TPolyVertex;
        Size: Double;
        Degree: Double;
    end;

    TPolyArray = array of TPolyVertex;  //多边型浮点数组类型

    TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
    private
        { Private declarations }
    public
        { Public declarations }
    end;

var
    Form1                               : TForm1;
    RandomPoly                          : TPolyArray;

implementation

{$R *.dfm}

procedure PloyRotate(var SrcPoly, DstPoly: TPolyArray; Value: Double);
var
    I, H                                : Integer;
    CosV, SinV                          : Double; //旋转变换
begin
    H := High(SrcPoly);
    SetLength(DstPoly, H + 1);
    CosV := Cos(Value); SinV := Sin(Value);
    for I := 0 to H do
    begin
        DstPoly[I].X := SrcPoly[I].X * CosV - SrcPoly[I].Y * SinV;
        DstPoly[I].Y := SrcPoly[I].X * SinV + SrcPoly[I].Y * CosV;
    end;
end;

function BuildMinRect(Poly: TPolyArray): TMinRect; //求最小水平包含矩形
var
    I                                   : Integer;
    HMin, HMax, VMin, VMax              : Double;
begin
    HMin := 999999999999; HMax := -999999999999;
    VMin := 999999999999; VMax := -999999999999;
    for I := 0 to High(Poly) do
    begin
        if Poly[I].X < HMin then HMin := Poly[I].X;
        if Poly[I].X > HMax then HMax := Poly[I].X;
        if Poly[I].Y < VMin then VMin := Poly[I].Y;
        if Poly[I].Y > VMax then VMax := Poly[I].Y;
    end;
    Result.p1.X := HMin; Result.p1.Y := VMin;
    Result.p2.X := HMax; Result.p2.Y := VMin;
    Result.p3.X := HMax; Result.p3.Y := VMax;
    Result.p4.X := HMin; Result.p4.Y := VMax;
    Result.Size := ((HMax - HMin) * (VMax - VMin));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    TempPoly                            : TPolyArray;
    I, J                                : Integer;
    SizeMin, Step, Degree               : Double;
    ARect, MinRect                      : TMinRect;
    RectPoly                            : TPolyArray;
begin
    J := Random(10) + 3;
    RandSeed := GetTickCount;
    SetLength(RandomPoly, J);
    for I := 0 to J - 1 do              //随机的多边形生成
    begin
        RandomPoly[I].X := Random(300) + 100;
        RandomPoly[I].Y := Random(300) + 50;
    end;
    Degree := 0;
    Step := PI / 720;      //精确度
    SizeMin := 9999999999999999;

    while Degree < PI do                //角度递增旋转
    begin
        PloyRotate(RandomPoly, TempPoly, Degree); //变换
        ARect := BuildMinRect(TempPoly); //求水平包含矩形
        if ARect.Size < SizeMin then
        begin
            SizeMin := ARect.Size;      //记录最小面积的包含矩形
            MinRect := ARect;
            MinRect.Degree := Degree;
        end;
        Degree := Degree + Step;
    end;

    SetLength(TempPoly, 4);
    TempPoly[0] := MinRect.p1; TempPoly[1] := MinRect.p2;
    TempPoly[2] := MinRect.p3; TempPoly[3] := MinRect.p4;
    PloyRotate(TempPoly, RectPoly, -MinRect.Degree); //反向变换结果矩形

    Canvas.Brush.Color := Clwhite;
    Canvas.Rectangle(Canvas.Cliprect);  //清除原内容

    Canvas.Pen.Color := ClBlue;         //画多边形
    Canvas.Moveto(Round(RandomPoly[0].X), Round(RandomPoly[0].Y));
    for I := 1 to J - 1 do
        Canvas.Lineto(Round(RandomPoly[I].X), Round(RandomPoly[I].Y));
    Canvas.Lineto(Round(RandomPoly[0].X), Round(RandomPoly[0].Y));

    Canvas.Pen.Color := ClRed;          //画包含矩形
    Canvas.Moveto(Round(RectPoly[0].X), Round(RectPoly[0].Y));
    for I := 1 to 3 do
        Canvas.Lineto(Round(RectPoly[I].X), Round(RectPoly[I].Y));
    Canvas.Lineto(Round(RectPoly[0].X), Round(RectPoly[0].Y));
    while Degree < PI do                //角度递增旋转
    begin
        PloyRotate(RandomPoly, TempPoly, Degree); //变换
        ARect := BuildMinRect(TempPoly); //求水平包含矩形
        if ARect.Size < SizeMin then
        begin
            SizeMin := ARect.Size;      //记录最小面积的包含矩形
            MinRect := ARect;
            MinRect.Degree := Degree;
        end;
        Degree := Degree + Step;
    end;

    SetLength(TempPoly, 4);
    TempPoly[0] := MinRect.p1;
    TempPoly[1] := MinRect.p2;
    TempPoly[2] := MinRect.p3;
    TempPoly[3] := MinRect.p4;
    PloyRotate(TempPoly, RectPoly, -MinRect.Degree); //反向变换结果矩形

    Canvas.Brush.Color := Clwhite;
    Canvas.Rectangle(Canvas.Cliprect);  //清除原内容

    Canvas.Pen.Color := ClBlue;         //画多边形
    Canvas.Moveto(Round(RandomPoly[0].X), Round(RandomPoly[0].Y));
    for I := 1 to J - 1 do
        Canvas.Lineto(Round(RandomPoly[I].X), Round(RandomPoly[I].Y));
    Canvas.Lineto(Round(RandomPoly[0].X), Round(RandomPoly[0].Y));

    Canvas.Pen.Color := ClRed;          //画包含矩形
    Canvas.Moveto(Round(RectPoly[0].X), Round(RectPoly[0].Y));
    for I := 1 to 3 do
        Canvas.Lineto(Round(RectPoly[I].X), Round(RectPoly[I].Y));
    Canvas.Lineto(Round(RectPoly[0].X), Round(RectPoly[0].Y));
end;

end.

 来自:http://www.delphibbs.com/delphibbs/dispq.asp?lid=320914

posted on 2011-03-14 10:46  gisai  阅读(2015)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3